7 #include "TFitResultPtr.h"
8 #include "TFitResult.h"
10 #include "AliMCParticle.h"
12 #include "AliAnalysisTask.h"
13 #include "AliAnalysisManager.h"
15 #include "AliESDEvent.h"
16 #include "AliMCEvent.h"
17 #include "AliESDtrackCuts.h"
18 #include "AliAnalysisFilter.h"
19 #include "AliInputEventHandler.h"
21 #include "AliVVertex.h"
23 #include "AliPIDCombined.h"
24 #include "AliPIDResponse.h"
25 #include "AliTPCPIDResponse.h"
27 #include "AliAnalysisTaskPID.h"
30 This task collects PID output from different detectors.
31 Only tracks fulfilling some standard quality cuts are taken into account.
32 At the moment, only data from TPC and TOF is collected. But in future,
33 data from e.g. HMPID is also foreseen.
35 Contact: bhess@cern.ch
38 ClassImp(AliAnalysisTaskPID)
40 const Int_t AliAnalysisTaskPID::fgkNumJetAxes = 3; // Number of additional axes for jets
41 const Double_t AliAnalysisTaskPID::fgkEpsilon = 1e-8; // Double_t threshold above zero
42 const Int_t AliAnalysisTaskPID::fgkMaxNumGenEntries = 500; // Maximum number of generated detector responses per track and delta(Prime) and associated species
44 const Double_t AliAnalysisTaskPID::fgkOneOverSqrt2 = 0.707106781186547462; // = 1. / TMath::Sqrt2();
46 const Double_t AliAnalysisTaskPID::fgkSigmaReferenceForTransitionPars = 0.05; // Reference sigma chosen to calculate transition
48 //________________________________________________________________________
49 AliAnalysisTaskPID::AliAnalysisTaskPID()
50 : AliAnalysisTaskPIDV0base()
52 , fPIDcombined(new AliPIDCombined())
53 , fInputFromOtherTask(kFALSE)
55 , fDoEfficiency(kTRUE)
56 , fDoPtResolution(kFALSE)
57 , fDoDeDxCheck(kFALSE)
58 , fDoBinZeroStudy(kFALSE)
59 , fStoreCentralityPercentile(kFALSE)
60 , fStoreAdditionalJetInformation(kFALSE)
61 , fTakeIntoAccountMuons(kFALSE)
65 , fTPCDefaultPriors(kFALSE)
66 , fUseMCidForGeneration(kTRUE)
67 , fUseConvolutedGaus(kFALSE)
68 , fkConvolutedGausNPar(3)
69 , fAccuracyNonGaussianTail(1e-8)
70 , fkDeltaPrimeLowLimit(0.02)
71 , fkDeltaPrimeUpLimit(40.0)
72 , fConvolutedGausDeltaPrime(0x0)
76 , fPileUpRejectionType(AliAnalysisTaskPIDV0base::kPileUpRejectionOff)
77 , fDoAnySystematicStudiesOnTheExpectedSignal(kFALSE)
78 , fSystematicScalingSplinesThreshold(50.)
79 , fSystematicScalingSplinesBelowThreshold(1.0)
80 , fSystematicScalingSplinesAboveThreshold(1.0)
81 , fSystematicScalingEtaCorrectionMomentumThr(0.35)
82 , fSystematicScalingEtaCorrectionLowMomenta(1.0)
83 , fSystematicScalingEtaCorrectionHighMomenta(1.0)
84 , fSystematicScalingEtaSigmaParaThreshold(250.)
85 , fSystematicScalingEtaSigmaParaBelowThreshold(1.0)
86 , fSystematicScalingEtaSigmaParaAboveThreshold(1.0)
87 , fSystematicScalingMultCorrection(1.0)
88 , fCentralityEstimator("V0M")
95 , fGenRespElDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
96 , fGenRespElDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
97 , fGenRespElDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
98 , fGenRespElDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
99 , fGenRespKaDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
100 , fGenRespKaDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
101 , fGenRespKaDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
102 , fGenRespKaDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
103 , fGenRespPiDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
104 , fGenRespPiDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
105 , fGenRespPiDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
106 , fGenRespPiDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
107 , fGenRespMuDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
108 , fGenRespMuDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
109 , fGenRespMuDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
110 , fGenRespMuDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
111 , fGenRespPrDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
112 , fGenRespPrDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
113 , fGenRespPrDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
114 , fGenRespPrDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
116 , fGenRespElDeltaEl(new Double_t[fgkMaxNumGenEntries])
117 , fGenRespElDeltaKa(new Double_t[fgkMaxNumGenEntries])
118 , fGenRespElDeltaPi(new Double_t[fgkMaxNumGenEntries])
119 , fGenRespElDeltaPr(new Double_t[fgkMaxNumGenEntries])
120 , fGenRespKaDeltaEl(new Double_t[fgkMaxNumGenEntries])
121 , fGenRespKaDeltaKa(new Double_t[fgkMaxNumGenEntries])
122 , fGenRespKaDeltaPi(new Double_t[fgkMaxNumGenEntries])
123 , fGenRespKaDeltaPr(new Double_t[fgkMaxNumGenEntries])
124 , fGenRespPiDeltaEl(new Double_t[fgkMaxNumGenEntries])
125 , fGenRespPiDeltaKa(new Double_t[fgkMaxNumGenEntries])
126 , fGenRespPiDeltaPi(new Double_t[fgkMaxNumGenEntries])
127 , fGenRespPiDeltaPr(new Double_t[fgkMaxNumGenEntries])
128 , fGenRespMuDeltaEl(new Double_t[fgkMaxNumGenEntries])
129 , fGenRespMuDeltaKa(new Double_t[fgkMaxNumGenEntries])
130 , fGenRespMuDeltaPi(new Double_t[fgkMaxNumGenEntries])
131 , fGenRespMuDeltaPr(new Double_t[fgkMaxNumGenEntries])
132 , fGenRespPrDeltaEl(new Double_t[fgkMaxNumGenEntries])
133 , fGenRespPrDeltaKa(new Double_t[fgkMaxNumGenEntries])
134 , fGenRespPrDeltaPi(new Double_t[fgkMaxNumGenEntries])
135 , fGenRespPrDeltaPr(new Double_t[fgkMaxNumGenEntries])
137 , fDeltaPrimeAxis(0x0)
138 , fhMaxEtaVariation(0x0)
139 , fhEventsProcessed(0x0)
140 , fhEventsTriggerSel(0x0)
141 , fhEventsTriggerSelVtxCut(0x0)
142 , fhEventsProcessedNoPileUpRejection(0x0)
143 , fChargedGenPrimariesTriggerSel(0x0)
144 , fChargedGenPrimariesTriggerSelVtxCut(0x0)
145 , fChargedGenPrimariesTriggerSelVtxCutZ(0x0)
146 , fChargedGenPrimariesTriggerSelVtxCutZPileUpRej(0x0)
147 , fhMCgeneratedYieldsPrimaries(0x0)
152 , fh1EvtsPtHardCut(0x0)
156 , fOutputContainer(0x0)
159 // default Constructor
161 AliLog::SetClassDebugLevel("AliAnalysisTaskPID", AliLog::kInfo);
163 fConvolutedGausDeltaPrime = new TF1("convolutedGausDeltaPrime", this, &AliAnalysisTaskPID::ConvolutedGaus,
164 fkDeltaPrimeLowLimit, fkDeltaPrimeUpLimit,
165 fkConvolutedGausNPar, "AliAnalysisTaskPID", "ConvolutedGaus");
167 // Set some arbitrary parameteres, such that the function call will not crash
168 // (although it should not be called with these parameters...)
169 fConvolutedGausDeltaPrime->SetParameter(0, 0);
170 fConvolutedGausDeltaPrime->SetParameter(1, 1);
171 fConvolutedGausDeltaPrime->SetParameter(2, 2);
174 // Initialisation of translation parameters is time consuming.
175 // Therefore, default values will only be initialised if they are really needed.
176 // Otherwise, it is left to the user to set the parameter properly.
177 fConvolutedGaussTransitionPars[0] = -999;
178 fConvolutedGaussTransitionPars[1] = -999;
179 fConvolutedGaussTransitionPars[2] = -999;
182 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
183 fFractionHists[i] = 0x0;
184 fFractionSysErrorHists[i] = 0x0;
186 fPtResolution[i] = 0x0;
190 //________________________________________________________________________
191 AliAnalysisTaskPID::AliAnalysisTaskPID(const char *name)
192 : AliAnalysisTaskPIDV0base(name)
194 , fPIDcombined(new AliPIDCombined())
195 , fInputFromOtherTask(kFALSE)
197 , fDoEfficiency(kTRUE)
198 , fDoPtResolution(kFALSE)
199 , fDoDeDxCheck(kFALSE)
200 , fDoBinZeroStudy(kFALSE)
201 , fStoreCentralityPercentile(kFALSE)
202 , fStoreAdditionalJetInformation(kFALSE)
203 , fTakeIntoAccountMuons(kFALSE)
207 , fTPCDefaultPriors(kFALSE)
208 , fUseMCidForGeneration(kTRUE)
209 , fUseConvolutedGaus(kFALSE)
210 , fkConvolutedGausNPar(3)
211 , fAccuracyNonGaussianTail(1e-8)
212 , fkDeltaPrimeLowLimit(0.02)
213 , fkDeltaPrimeUpLimit(40.0)
214 , fConvolutedGausDeltaPrime(0x0)
218 , fPileUpRejectionType(AliAnalysisTaskPIDV0base::kPileUpRejectionOff)
219 , fDoAnySystematicStudiesOnTheExpectedSignal(kFALSE)
220 , fSystematicScalingSplinesThreshold(50.)
221 , fSystematicScalingSplinesBelowThreshold(1.0)
222 , fSystematicScalingSplinesAboveThreshold(1.0)
223 , fSystematicScalingEtaCorrectionMomentumThr(0.35)
224 , fSystematicScalingEtaCorrectionLowMomenta(1.0)
225 , fSystematicScalingEtaCorrectionHighMomenta(1.0)
226 , fSystematicScalingEtaSigmaParaThreshold(250.)
227 , fSystematicScalingEtaSigmaParaBelowThreshold(1.0)
228 , fSystematicScalingEtaSigmaParaAboveThreshold(1.0)
229 , fSystematicScalingMultCorrection(1.0)
230 , fCentralityEstimator("V0M")
237 , fGenRespElDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
238 , fGenRespElDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
239 , fGenRespElDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
240 , fGenRespElDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
241 , fGenRespKaDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
242 , fGenRespKaDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
243 , fGenRespKaDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
244 , fGenRespKaDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
245 , fGenRespPiDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
246 , fGenRespPiDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
247 , fGenRespPiDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
248 , fGenRespPiDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
249 , fGenRespMuDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
250 , fGenRespMuDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
251 , fGenRespMuDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
252 , fGenRespMuDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
253 , fGenRespPrDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
254 , fGenRespPrDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
255 , fGenRespPrDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
256 , fGenRespPrDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
258 , fGenRespElDeltaEl(new Double_t[fgkMaxNumGenEntries])
259 , fGenRespElDeltaKa(new Double_t[fgkMaxNumGenEntries])
260 , fGenRespElDeltaPi(new Double_t[fgkMaxNumGenEntries])
261 , fGenRespElDeltaPr(new Double_t[fgkMaxNumGenEntries])
262 , fGenRespKaDeltaEl(new Double_t[fgkMaxNumGenEntries])
263 , fGenRespKaDeltaKa(new Double_t[fgkMaxNumGenEntries])
264 , fGenRespKaDeltaPi(new Double_t[fgkMaxNumGenEntries])
265 , fGenRespKaDeltaPr(new Double_t[fgkMaxNumGenEntries])
266 , fGenRespPiDeltaEl(new Double_t[fgkMaxNumGenEntries])
267 , fGenRespPiDeltaKa(new Double_t[fgkMaxNumGenEntries])
268 , fGenRespPiDeltaPi(new Double_t[fgkMaxNumGenEntries])
269 , fGenRespPiDeltaPr(new Double_t[fgkMaxNumGenEntries])
270 , fGenRespMuDeltaEl(new Double_t[fgkMaxNumGenEntries])
271 , fGenRespMuDeltaKa(new Double_t[fgkMaxNumGenEntries])
272 , fGenRespMuDeltaPi(new Double_t[fgkMaxNumGenEntries])
273 , fGenRespMuDeltaPr(new Double_t[fgkMaxNumGenEntries])
274 , fGenRespPrDeltaEl(new Double_t[fgkMaxNumGenEntries])
275 , fGenRespPrDeltaKa(new Double_t[fgkMaxNumGenEntries])
276 , fGenRespPrDeltaPi(new Double_t[fgkMaxNumGenEntries])
277 , fGenRespPrDeltaPr(new Double_t[fgkMaxNumGenEntries])
279 , fDeltaPrimeAxis(0x0)
280 , fhMaxEtaVariation(0x0)
281 , fhEventsProcessed(0x0)
282 , fhEventsTriggerSel(0x0)
283 , fhEventsTriggerSelVtxCut(0x0)
284 , fhEventsProcessedNoPileUpRejection(0x0)
285 , fChargedGenPrimariesTriggerSel(0x0)
286 , fChargedGenPrimariesTriggerSelVtxCut(0x0)
287 , fChargedGenPrimariesTriggerSelVtxCutZ(0x0)
288 , fChargedGenPrimariesTriggerSelVtxCutZPileUpRej(0x0)
289 , fhMCgeneratedYieldsPrimaries(0x0)
294 , fh1EvtsPtHardCut(0x0)
298 , fOutputContainer(0x0)
303 AliLog::SetClassDebugLevel("AliAnalysisTaskPID", AliLog::kInfo);
305 fConvolutedGausDeltaPrime = new TF1("convolutedGausDeltaPrime", this, &AliAnalysisTaskPID::ConvolutedGaus,
306 fkDeltaPrimeLowLimit, fkDeltaPrimeUpLimit,
307 fkConvolutedGausNPar, "AliAnalysisTaskPID", "ConvolutedGaus");
309 // Set some arbitrary parameteres, such that the function call will not crash
310 // (although it should not be called with these parameters...)
311 fConvolutedGausDeltaPrime->SetParameter(0, 0);
312 fConvolutedGausDeltaPrime->SetParameter(1, 1);
313 fConvolutedGausDeltaPrime->SetParameter(2, 2);
316 // Initialisation of translation parameters is time consuming.
317 // Therefore, default values will only be initialised if they are really needed.
318 // Otherwise, it is left to the user to set the parameter properly.
319 fConvolutedGaussTransitionPars[0] = -999;
320 fConvolutedGaussTransitionPars[1] = -999;
321 fConvolutedGaussTransitionPars[2] = -999;
324 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
325 fFractionHists[i] = 0x0;
326 fFractionSysErrorHists[i] = 0x0;
328 fPtResolution[i] = 0x0;
331 // Define input and output slots here
332 // Input slot #0 works with a TChain
333 DefineInput(0, TChain::Class());
335 DefineOutput(1, TObjArray::Class());
337 DefineOutput(2, AliCFContainer::Class());
339 DefineOutput(3, TObjArray::Class());
343 //________________________________________________________________________
344 AliAnalysisTaskPID::~AliAnalysisTaskPID()
348 CleanupParticleFractionHistos();
350 delete fOutputContainer;
351 fOutputContainer = 0x0;
356 delete fConvolutedGausDeltaPrime;
357 fConvolutedGausDeltaPrime = 0x0;
359 delete fDeltaPrimeAxis;
360 fDeltaPrimeAxis = 0x0;
362 delete [] fGenRespElDeltaPrimeEl;
363 delete [] fGenRespElDeltaPrimeKa;
364 delete [] fGenRespElDeltaPrimePi;
365 delete [] fGenRespElDeltaPrimePr;
367 fGenRespElDeltaPrimeEl = 0x0;
368 fGenRespElDeltaPrimeKa = 0x0;
369 fGenRespElDeltaPrimePi = 0x0;
370 fGenRespElDeltaPrimePr = 0x0;
372 delete [] fGenRespKaDeltaPrimeEl;
373 delete [] fGenRespKaDeltaPrimeKa;
374 delete [] fGenRespKaDeltaPrimePi;
375 delete [] fGenRespKaDeltaPrimePr;
377 fGenRespKaDeltaPrimeEl = 0x0;
378 fGenRespKaDeltaPrimeKa = 0x0;
379 fGenRespKaDeltaPrimePi = 0x0;
380 fGenRespKaDeltaPrimePr = 0x0;
382 delete [] fGenRespPiDeltaPrimeEl;
383 delete [] fGenRespPiDeltaPrimeKa;
384 delete [] fGenRespPiDeltaPrimePi;
385 delete [] fGenRespPiDeltaPrimePr;
387 fGenRespPiDeltaPrimeEl = 0x0;
388 fGenRespPiDeltaPrimeKa = 0x0;
389 fGenRespPiDeltaPrimePi = 0x0;
390 fGenRespPiDeltaPrimePr = 0x0;
392 delete [] fGenRespMuDeltaPrimeEl;
393 delete [] fGenRespMuDeltaPrimeKa;
394 delete [] fGenRespMuDeltaPrimePi;
395 delete [] fGenRespMuDeltaPrimePr;
397 fGenRespMuDeltaPrimeEl = 0x0;
398 fGenRespMuDeltaPrimeKa = 0x0;
399 fGenRespMuDeltaPrimePi = 0x0;
400 fGenRespMuDeltaPrimePr = 0x0;
402 delete [] fGenRespPrDeltaPrimeEl;
403 delete [] fGenRespPrDeltaPrimeKa;
404 delete [] fGenRespPrDeltaPrimePi;
405 delete [] fGenRespPrDeltaPrimePr;
407 fGenRespPrDeltaPrimeEl = 0x0;
408 fGenRespPrDeltaPrimeKa = 0x0;
409 fGenRespPrDeltaPrimePi = 0x0;
410 fGenRespPrDeltaPrimePr = 0x0;
412 delete fhMaxEtaVariation;
413 fhMaxEtaVariation = 0x0;
415 /*OLD with deltaSpecies
416 delete [] fGenRespElDeltaEl;
417 delete [] fGenRespElDeltaKa;
418 delete [] fGenRespElDeltaPi;
419 delete [] fGenRespElDeltaPr;
421 fGenRespElDeltaEl = 0x0;
422 fGenRespElDeltaKa = 0x0;
423 fGenRespElDeltaPi = 0x0;
424 fGenRespElDeltaPr = 0x0;
426 delete [] fGenRespKaDeltaEl;
427 delete [] fGenRespKaDeltaKa;
428 delete [] fGenRespKaDeltaPi;
429 delete [] fGenRespKaDeltaPr;
431 fGenRespKaDeltaEl = 0x0;
432 fGenRespKaDeltaKa = 0x0;
433 fGenRespKaDeltaPi = 0x0;
434 fGenRespKaDeltaPr = 0x0;
436 delete [] fGenRespPiDeltaEl;
437 delete [] fGenRespPiDeltaKa;
438 delete [] fGenRespPiDeltaPi;
439 delete [] fGenRespPiDeltaPr;
441 fGenRespPiDeltaEl = 0x0;
442 fGenRespPiDeltaKa = 0x0;
443 fGenRespPiDeltaPi = 0x0;
444 fGenRespPiDeltaPr = 0x0;
446 delete [] fGenRespMuDeltaEl;
447 delete [] fGenRespMuDeltaKa;
448 delete [] fGenRespMuDeltaPi;
449 delete [] fGenRespMuDeltaPr;
451 fGenRespMuDeltaEl = 0x0;
452 fGenRespMuDeltaKa = 0x0;
453 fGenRespMuDeltaPi = 0x0;
454 fGenRespMuDeltaPr = 0x0;
456 delete [] fGenRespPrDeltaEl;
457 delete [] fGenRespPrDeltaKa;
458 delete [] fGenRespPrDeltaPi;
459 delete [] fGenRespPrDeltaPr;
461 fGenRespPrDeltaEl = 0x0;
462 fGenRespPrDeltaKa = 0x0;
463 fGenRespPrDeltaPi = 0x0;
464 fGenRespPrDeltaPr = 0x0;
469 //________________________________________________________________________
470 void AliAnalysisTaskPID::SetUpPIDcombined()
472 // Initialise the PIDcombined object
474 if (!fDoPID && !fDoDeDxCheck)
478 printf("File: %s, Line: %d: SetUpPIDcombined\n", (char*)__FILE__, __LINE__);
481 AliFatal("No PIDcombined object!\n");
485 fPIDcombined->SetSelectedSpecies(AliPID::kSPECIESC);
486 fPIDcombined->SetEnablePriors(fUsePriors);
488 if (fTPCDefaultPriors)
489 fPIDcombined->SetDefaultTPCPriors();
491 //TODO use individual priors...
493 // Change detector mask (TPC,TOF,ITS)
494 Int_t detectorMask = AliPIDResponse::kDetTPC;
496 // Reject mismatch mask - mismatch only relevant for TOF at the moment - other detectors do not use it
497 Int_t rejectMismatchMask = AliPIDResponse::kDetTPC;
501 detectorMask = detectorMask | AliPIDResponse::kDetITS;
502 rejectMismatchMask = rejectMismatchMask | AliPIDResponse::kDetITS;
505 detectorMask = detectorMask | AliPIDResponse::kDetTOF;
506 rejectMismatchMask = rejectMismatchMask | AliPIDResponse::kDetTOF;
509 fPIDcombined->SetDetectorMask(detectorMask);
510 fPIDcombined->SetRejectMismatchMask(rejectMismatchMask);
513 printf("File: %s, Line: %d: SetUpPIDcombined done\n", (char*)__FILE__, __LINE__);
517 //________________________________________________________________________
518 Bool_t AliAnalysisTaskPID::CalculateMaxEtaVariationMapFromPIDResponse()
520 // Calculate the maximum deviation from unity of the eta correction factors for each row in 1/dEdx(splines)
521 // from the eta correction map of the TPCPIDResponse. The result is stored in fhMaxEtaVariation.
524 AliError("No PID response!");
528 delete fhMaxEtaVariation;
530 const TH2D* hEta = fPIDResponse->GetTPCResponse().GetEtaCorrMap();
532 AliError("No eta correction map!");
536 // Take binning from hEta in Y for fhMaxEtaVariation
537 fhMaxEtaVariation = hEta->ProjectionY("hMaxEtaVariation");
538 fhMaxEtaVariation->SetDirectory(0);
539 fhMaxEtaVariation->Reset();
541 // For each bin in 1/dEdx, loop of all tanTheta bins and find the maximum deviation from unity.
542 // Store the result in fhMaxEtaVariation
544 for (Int_t binY = 1; binY <= fhMaxEtaVariation->GetNbinsX(); binY++) {
545 Double_t maxAbs = -1;
546 for (Int_t binX = 1; binX <= hEta->GetNbinsX(); binX++) {
547 Double_t curr = TMath::Abs(hEta->GetBinContent(binX, binY) - 1.);
552 if (maxAbs < 1e-12) {
553 AliError(Form("Maximum deviation from unity is zero for 1/dEdx = %f (bin %d)", hEta->GetYaxis()->GetBinCenter(binY), binY));
554 delete fhMaxEtaVariation;
558 fhMaxEtaVariation->SetBinContent(binY, maxAbs);
561 printf("AliAnalysisTaskPID: Calculated max eta variation from map \"%s\".\n", hEta->GetTitle());
567 //________________________________________________________________________
568 void AliAnalysisTaskPID::UserCreateOutputObjects()
574 printf("File: %s, Line: %d: UserCreateOutputObjects\n", (char*)__FILE__, __LINE__);
576 // Setup basic things, like PIDResponse
577 AliAnalysisTaskPIDV0base::UserCreateOutputObjects();
580 AliFatal("PIDResponse object was not created");
587 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(1) successful\n", (char*)__FILE__, __LINE__);
589 fOutputContainer = new TObjArray(1);
590 fOutputContainer->SetName(GetName());
591 fOutputContainer->SetOwner(kTRUE);
593 const Int_t nPtBins = 68;
594 Double_t binsPt[nPtBins+1] = {0. , 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45,
595 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95,
596 1.0, 1.1 , 1.2, 1.3 , 1.4, 1.5 , 1.6, 1.7 , 1.8, 1.9 ,
597 2.0, 2.2 , 2.4, 2.6 , 2.8, 3.0 , 3.2, 3.4 , 3.6, 3.8 ,
598 4.0, 4.5 , 5.0, 5.5 , 6.0, 6.5 , 7.0, 8.0 , 9.0, 10.0,
599 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0,
600 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0 };
602 const Bool_t useITSTPCtrackletsCentEstimatorWithNewBinning = fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0
603 && fStoreCentralityPercentile;
605 const Int_t nCentBinsGeneral = 12;
606 const Int_t nCentBinsNewITSTPCtracklets = 17;
608 const Int_t nCentBins = useITSTPCtrackletsCentEstimatorWithNewBinning ? nCentBinsNewITSTPCtracklets : nCentBinsGeneral;
610 Double_t binsCent[nCentBins+1];
611 for (Int_t i = 0; i < nCentBins + 1; i++)
614 //-1 for pp (unless explicitely requested); 90-100 has huge electro-magnetic impurities
615 Double_t binsCentV0[nCentBinsGeneral+1] = {-1, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
617 // These centrality estimators deal with integers! This implies that the ranges are always [lowlim, uplim - 1]
618 Double_t binsCentITSTPCTracklets[nCentBinsNewITSTPCtracklets+1] = { -9999, 0, 1, 4, 7, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 9999 };
619 Double_t binsCentITSTPCTrackletsOldPreliminary[nCentBinsGeneral+1] = { 0, 7, 13, 20, 29, 40, 50, 60, 72, 83, 95, 105, 115 };
621 // Special centrality binning for pp
622 Double_t binsCentpp[nCentBinsGeneral+1] = { 0, 0.01, 0.1, 1, 5, 10, 15, 20, 30, 40, 50, 70, 100};
624 if (fCentralityEstimator.CompareTo("ITSTPCtrackletsOldPreliminaryBinning", TString::kIgnoreCase) == 0 && fStoreCentralityPercentile) {
625 // Special binning for this centrality estimator; but keep number of bins!
626 for (Int_t i = 0; i < nCentBinsGeneral+1; i++)
627 binsCent[i] = binsCentITSTPCTrackletsOldPreliminary[i];
629 else if (fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0 && fStoreCentralityPercentile) {
630 // Special binning for this centrality estimator and different number of bins!
631 for (Int_t i = 0; i < nCentBinsNewITSTPCtracklets+1; i++)
632 binsCent[i] = binsCentITSTPCTracklets[i];
634 else if (fCentralityEstimator.Contains("ppMult", TString::kIgnoreCase) && fStoreCentralityPercentile) {
635 // Special binning for this pp centrality estimator; but keep number of bins!
636 for (Int_t i = 0; i < nCentBinsGeneral+1; i++)
637 binsCent[i] = binsCentpp[i];
640 // Take default binning for VZERO
641 for (Int_t i = 0; i < nCentBinsGeneral+1; i++)
642 binsCent[i] = binsCentV0[i];
645 const Int_t nJetPtBins = 11;
646 Double_t binsJetPt[nJetPtBins+1] = {0, 2, 5, 10, 15, 20, 30, 40, 60, 80, 120, 200};
648 const Int_t nChargeBins = 2;
649 const Double_t binsCharge[nChargeBins+1] = { -1.0 - 1e-4, 0.0, 1.0 + 1e-4 };
651 const Int_t nBinsJets = kDataNumAxes;
652 const Int_t nBinsNoJets = nBinsJets - fgkNumJetAxes;
654 const Int_t nBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
656 // deltaPrimeSpecies binning
657 const Int_t deltaPrimeNBins = 600;
658 Double_t deltaPrimeBins[deltaPrimeNBins + 1];
660 const Double_t fromLow = fkDeltaPrimeLowLimit;
661 const Double_t toHigh = fkDeltaPrimeUpLimit;
662 const Double_t factor = TMath::Power(toHigh/fromLow, 1./deltaPrimeNBins);
664 // Log binning for whole deltaPrime range
665 deltaPrimeBins[0] = fromLow;
666 for (Int_t i = 0 + 1; i <= deltaPrimeNBins; i++) {
667 deltaPrimeBins[i] = factor * deltaPrimeBins[i - 1];
670 fDeltaPrimeAxis = new TAxis(deltaPrimeNBins, deltaPrimeBins);
672 const Int_t nMCPIDbins = 5;
673 const Double_t mcPIDmin = 0.;
674 const Double_t mcPIDmax = 5.;
676 const Int_t nSelSpeciesBins = 4;
677 const Double_t selSpeciesMin = 0.;
678 const Double_t selSpeciesMax = 4.;
680 const Int_t nZBins = 20;
681 const Double_t zMin = 0.;
682 const Double_t zMax = 1.;
684 const Int_t nXiBins = 70;
685 const Double_t xiMin = 0.;
686 const Double_t xiMax = 7.;
688 const Int_t nTOFpidInfoBins = kNumTOFpidInfoBins;
689 const Double_t tofPIDinfoMin = kNoTOFinfo;
690 const Double_t tofPIDinfoMax = kNoTOFinfo + kNumTOFpidInfoBins;
692 // MC PID, SelectSpecies, pT, deltaPrimeSpecies, centrality percentile, jet pT, z = track_pT/jet_pT, xi = log(1/z)
693 Int_t binsNoJets[nBinsNoJets] = { nMCPIDbins,
701 Int_t binsJets[nBinsJets] = { nMCPIDbins,
712 Int_t *bins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
714 Double_t xminNoJets[nBinsNoJets] = { mcPIDmin,
722 Double_t xminJets[nBinsJets] = { mcPIDmin,
733 Double_t *xmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
735 Double_t xmaxNoJets[nBinsNoJets] = { mcPIDmax,
738 deltaPrimeBins[deltaPrimeNBins],
740 binsCharge[nChargeBins],
743 Double_t xmaxJets[nBinsJets] = { mcPIDmax,
746 deltaPrimeBins[deltaPrimeNBins],
748 binsJetPt[nJetPtBins],
751 binsCharge[nChargeBins],
754 Double_t *xmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
756 fConvolutedGausDeltaPrime->SetNpx(deltaPrimeNBins);
759 fhPIDdataAll = new THnSparseD("hPIDdataAll","", nBins, bins, xmin, xmax);
760 SetUpHist(fhPIDdataAll, binsPt, deltaPrimeBins, binsCent, binsJetPt);
761 fOutputContainer->Add(fhPIDdataAll);
764 // Generated histograms (so far, bins are the same as for primary THnSparse)
765 const Int_t nGenBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
766 // MC PID, SelectSpecies, Pt, deltaPrimeSpecies, jet pT, z = track_pT/jet_pT, xi = log(1/z)
768 Int_t *genBins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
769 Double_t *genXmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
770 Double_t *genXmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
773 fhGenEl = new THnSparseD("hGenEl", "", nGenBins, genBins, genXmin, genXmax);
774 SetUpGenHist(fhGenEl, binsPt, deltaPrimeBins, binsCent, binsJetPt);
775 fOutputContainer->Add(fhGenEl);
777 fhGenKa = new THnSparseD("hGenKa", "", nGenBins, genBins, genXmin, genXmax);
778 SetUpGenHist(fhGenKa, binsPt, deltaPrimeBins, binsCent, binsJetPt);
779 fOutputContainer->Add(fhGenKa);
781 fhGenPi = new THnSparseD("hGenPi", "", nGenBins, genBins, genXmin, genXmax);
782 SetUpGenHist(fhGenPi, binsPt, deltaPrimeBins, binsCent, binsJetPt);
783 fOutputContainer->Add(fhGenPi);
785 if (fTakeIntoAccountMuons) {
786 fhGenMu = new THnSparseD("hGenMu", "", nGenBins, genBins, genXmin, genXmax);
787 SetUpGenHist(fhGenMu, binsPt, deltaPrimeBins, binsCent, binsJetPt);
788 fOutputContainer->Add(fhGenMu);
791 fhGenPr = new THnSparseD("hGenPr", "", nGenBins, genBins, genXmin, genXmax);
792 SetUpGenHist(fhGenPr, binsPt, deltaPrimeBins, binsCent, binsJetPt);
793 fOutputContainer->Add(fhGenPr);
797 fhEventsProcessed = new TH1D("fhEventsProcessed",
798 "Number of events passing trigger selection, vtx and zvtx cuts and pile-up rejection;Centrality Percentile",
799 nCentBins, binsCent);
800 fhEventsProcessed->Sumw2();
801 fOutputContainer->Add(fhEventsProcessed);
803 fhEventsTriggerSelVtxCut = new TH1D("fhEventsTriggerSelVtxCut",
804 "Number of events passing trigger selection and vtx cut;Centrality Percentile",
805 nCentBins, binsCent);
806 fhEventsTriggerSelVtxCut->Sumw2();
807 fOutputContainer->Add(fhEventsTriggerSelVtxCut);
809 fhEventsTriggerSel = new TH1D("fhEventsTriggerSel",
810 "Number of events passing trigger selection;Centrality Percentile",
811 nCentBins, binsCent);
812 fOutputContainer->Add(fhEventsTriggerSel);
813 fhEventsTriggerSel->Sumw2();
816 fhEventsProcessedNoPileUpRejection = new TH1D("fhEventsProcessedNoPileUpRejection",
817 "Number of events passing trigger selection, vtx and zvtx cuts;Centrality Percentile",
818 nCentBins, binsCent);
819 fOutputContainer->Add(fhEventsProcessedNoPileUpRejection);
820 fhEventsProcessedNoPileUpRejection->Sumw2();
823 // Generated yields within acceptance
824 const Int_t nBinsGenYields = fStoreAdditionalJetInformation ? kGenYieldNumAxes : kGenYieldNumAxes - 3;
825 Int_t genYieldsBins[kGenYieldNumAxes] = { nMCPIDbins, nPtBins, nCentBins, nJetPtBins, nZBins, nXiBins,
827 genYieldsBins[GetIndexOfChargeAxisGenYield()] = nChargeBins;
828 Double_t genYieldsXmin[kGenYieldNumAxes] = { mcPIDmin, binsPt[0], binsCent[0], binsJetPt[0], zMin, xiMin,
830 genYieldsXmin[GetIndexOfChargeAxisGenYield()] = binsCharge[0];
831 Double_t genYieldsXmax[kGenYieldNumAxes] = { mcPIDmax, binsPt[nPtBins], binsCent[nCentBins], binsJetPt[nJetPtBins], zMax, xiMax,
832 binsCharge[nChargeBins] };
833 genYieldsXmax[GetIndexOfChargeAxisGenYield()] = binsCharge[nChargeBins];
836 fhMCgeneratedYieldsPrimaries = new THnSparseD("fhMCgeneratedYieldsPrimaries",
837 "Generated yields w/o reco and cuts inside acceptance (physical primaries)",
838 nBinsGenYields, genYieldsBins, genYieldsXmin, genYieldsXmax);
839 SetUpGenYieldHist(fhMCgeneratedYieldsPrimaries, binsPt, binsCent, binsJetPt);
840 fOutputContainer->Add(fhMCgeneratedYieldsPrimaries);
843 // Container with several process steps (generated and reconstructed level with some variations)
848 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(2) successful\n", (char*)__FILE__, __LINE__);
850 // Array for the number of bins in each dimension
851 // Dimensions: MC-ID, trackPt, trackEta, trackCharge, cenrality percentile, jetPt, z, xi TODO phi???
852 const Int_t nEffDims = fStoreAdditionalJetInformation ? kEffNumAxes : kEffNumAxes - 3; // Number of dimensions for the efficiency
854 const Int_t nMCIDbins = AliPID::kSPECIES;
855 Double_t binsMCID[nMCIDbins + 1];
857 for(Int_t i = 0; i <= nMCIDbins; i++) {
861 const Int_t nEtaBins = 18;
862 const Double_t binsEta[nEtaBins+1] = {-0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
863 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };
865 const Int_t nEffBins[kEffNumAxes] = { nMCIDbins, nPtBins, nEtaBins, nChargeBins, nCentBins, nJetPtBins, nZBins, nXiBins };
867 fContainerEff = new AliCFContainer("containerEff", "Reconstruction Efficiency x Acceptance x Resolution and Secondary Correction",
868 kNumSteps, nEffDims, nEffBins);
870 // Setting the bin limits
871 fContainerEff->SetBinLimits(kEffMCID, binsMCID);
872 fContainerEff->SetBinLimits(kEffTrackPt, binsPt);
873 fContainerEff->SetBinLimits(kEffTrackEta, binsEta);
874 fContainerEff->SetBinLimits(kEffTrackCharge, binsCharge);
875 fContainerEff->SetBinLimits(kEffCentrality, binsCent);
876 if (fStoreAdditionalJetInformation) {
877 fContainerEff->SetBinLimits(kEffJetPt, binsJetPt);
878 fContainerEff->SetBinLimits(kEffZ, zMin, zMax);
879 fContainerEff->SetBinLimits(kEffXi, xiMin, xiMax);
882 fContainerEff->SetVarTitle(kEffMCID,"MC ID");
883 fContainerEff->SetVarTitle(kEffTrackPt,"p_{T} (GeV/c)");
884 fContainerEff->SetVarTitle(kEffTrackEta,"#eta");
885 fContainerEff->SetVarTitle(kEffTrackCharge,"Charge (e_{0})");
886 fContainerEff->SetVarTitle(kEffCentrality, "Centrality Percentile");
887 if (fStoreAdditionalJetInformation) {
888 fContainerEff->SetVarTitle(kEffJetPt, "p_{T}^{jet} (GeV/c)");
889 fContainerEff->SetVarTitle(kEffZ, "z = p_{T}^{track} / p_{T}^{jet}");
890 fContainerEff->SetVarTitle(kEffXi, "#xi = ln(p_{T}^{jet} / p_{T}^{track})");
893 // Define clean MC sample
894 fContainerEff->SetStepTitle(kStepGenWithGenCuts, "Particle level, cuts on particle level");
895 // For Acceptance x Efficiency correction of primaries
896 fContainerEff->SetStepTitle(kStepRecWithGenCuts, "Detector level (rec) with cuts on particle level");
897 // For (pT) resolution correction
898 fContainerEff->SetStepTitle(kStepRecWithGenCutsMeasuredObs,
899 "Detector level (rec) with cuts on particle level with measured observables");
900 // For secondary correction
901 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObs,
902 "Detector level, all cuts on detector level with measured observables");
903 fContainerEff->SetStepTitle(kStepRecWithRecCutsPrimaries,
904 "Detector level, all cuts on detector level, only MC primaries");
905 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsPrimaries,
906 "Detector level, all cuts on detector level with measured observables, only MC primaries");
907 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsStrangenessScaled,
908 "Detector level (strangeness scaled), all cuts on detector level with measured observables");
911 if (fDoPID || fDoEfficiency) {
913 fh2FFJetPtRec = new TH2D("fh2FFJetPtRec", "Number of reconstructed jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
914 nCentBins, binsCent, nJetPtBins, binsJetPt);
915 fh2FFJetPtRec->Sumw2();
916 fOutputContainer->Add(fh2FFJetPtRec);
917 fh2FFJetPtGen = new TH2D("fh2FFJetPtGen", "Number of generated jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
918 nCentBins, binsCent, nJetPtBins, binsJetPt);
919 fh2FFJetPtGen->Sumw2();
920 fOutputContainer->Add(fh2FFJetPtGen);
923 // Pythia information
924 fh1Xsec = new TProfile("fh1Xsec", "xsec from pyxsec.root", 1, 0, 1);
926 fh1Xsec->GetXaxis()->SetBinLabel(1, "<#sigma>");
927 fh1Trials = new TH1D("fh1Trials", "trials from pyxsec.root", 1, 0, 1);
929 fh1Trials->GetXaxis()->SetBinLabel(1, "#sum{ntrials}");
931 fh1EvtsPtHardCut = new TH1F("fh1EvtsPtHardCut", "#events before and after MC #it{p}_{T,hard} cut;;Events",2,0,2);
932 fh1EvtsPtHardCut->Sumw2();
933 fh1EvtsPtHardCut->GetXaxis()->SetBinLabel(1, "All");
934 fh1EvtsPtHardCut->GetXaxis()->SetBinLabel(2, "#it{p}_{T,hard}");
936 fOutputContainer->Add(fh1Xsec);
937 fOutputContainer->Add(fh1Trials);
938 fOutputContainer->Add(fh1EvtsPtHardCut);
940 if (fDoDeDxCheck || fDoPtResolution) {
942 fQAContainer = new TObjArray(1);
943 fQAContainer->SetName(Form("%s_QA", GetName()));
944 fQAContainer->SetOwner(kTRUE);
947 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(3) successful\n", (char*)__FILE__, __LINE__);
950 if (fDoPtResolution) {
951 const Int_t nPtBinsRes = 100;
952 Double_t pTbinsRes[nPtBinsRes + 1];
954 const Double_t fromLowPtRes = 0.15;
955 const Double_t toHighPtRes = 50.;
956 const Double_t factorPtRes = TMath::Power(toHighPtRes/fromLowPtRes, 1./nPtBinsRes);
957 // Log binning for whole pT range
958 pTbinsRes[0] = fromLowPtRes;
959 for (Int_t i = 0 + 1; i <= nPtBinsRes; i++) {
960 pTbinsRes[i] = factorPtRes * pTbinsRes[i - 1];
963 const Int_t nBinsPtResolution = kPtResNumAxes;
964 Int_t ptResolutionBins[kPtResNumAxes] = { nJetPtBins, nPtBinsRes, nPtBinsRes,
965 nChargeBins, nCentBins };
966 Double_t ptResolutionXmin[kPtResNumAxes] = { binsJetPt[0], pTbinsRes[0], pTbinsRes[0],
967 binsCharge[0], binsCent[0] };
968 Double_t ptResolutionXmax[kPtResNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], pTbinsRes[nPtBinsRes],
969 binsCharge[nChargeBins], binsCent[nCentBins] };
971 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
972 fPtResolution[i] = new THnSparseD(Form("fPtResolution_%s", AliPID::ParticleShortName(i)),
973 Form("Pt resolution for primaries, %s", AliPID::ParticleLatexName(i)),
974 nBinsPtResolution, ptResolutionBins, ptResolutionXmin, ptResolutionXmax);
975 SetUpPtResHist(fPtResolution[i], pTbinsRes, binsJetPt, binsCent);
976 fQAContainer->Add(fPtResolution[i]);
980 // Besides the pT resolution, also perform check on shared clusters
981 const Int_t nBinsQASharedCls = kQASharedClsNumAxes;
982 Int_t qaSharedClsBins[kQASharedClsNumAxes] = { nJetPtBins, nPtBinsRes, 160, 160 };
983 Double_t qaSharedClsXmin[kQASharedClsNumAxes] = { binsJetPt[0], pTbinsRes[0], 0, -1 };
984 Double_t qaSharedClsXmax[kQASharedClsNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], 160, 159 };
986 fQASharedCls = new THnSparseD("fQASharedCls", "QA shared clusters", nBinsQASharedCls, qaSharedClsBins, qaSharedClsXmin, qaSharedClsXmax);
988 SetUpSharedClsHist(fQASharedCls, pTbinsRes, binsJetPt);
989 fQAContainer->Add(fQASharedCls);
995 const Int_t nEtaAbsBins = 9;
996 const Double_t binsEtaAbs[nEtaAbsBins+1] = { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };
998 const Double_t dEdxMin = 20;
999 const Double_t dEdxMax = 110;
1000 const Int_t nDeDxBins = (Int_t) ((dEdxMax - dEdxMin) / 0.02);
1001 const Int_t nBinsDeDxCheck= kDeDxCheckNumAxes;
1002 Int_t dEdxCheckBins[kDeDxCheckNumAxes] = { nSelSpeciesBins, nPtBins, nJetPtBins, nEtaAbsBins, nDeDxBins };
1003 Double_t dEdxCheckXmin[kDeDxCheckNumAxes] = { selSpeciesMin, binsPt[0], binsJetPt[0], binsEtaAbs[0], dEdxMin };
1004 Double_t dEdxCheckXmax[kDeDxCheckNumAxes] = { selSpeciesMax, binsPt[nPtBins], binsJetPt[nJetPtBins], binsEtaAbs[nEtaAbsBins], dEdxMax };
1006 fDeDxCheck = new THnSparseD("fDeDxCheck", "dEdx check", nBinsDeDxCheck, dEdxCheckBins, dEdxCheckXmin, dEdxCheckXmax);
1007 SetUpDeDxCheckHist(fDeDxCheck, binsPt, binsJetPt, binsEtaAbs);
1008 fQAContainer->Add(fDeDxCheck);
1011 if (fDoBinZeroStudy) {
1012 const Double_t etaLow = -0.9;
1013 const Double_t etaUp = 0.9;
1014 const Int_t nEtaBins = 18;
1016 const Int_t nBinsBinZeroStudy = kBinZeroStudyNumAxes;
1017 Int_t binZeroStudyBins[nBinsBinZeroStudy] = { nCentBins, nPtBins, nEtaBins };
1018 Double_t binZeroStudyXmin[nBinsBinZeroStudy] = { binsCent[0], binsPt[0], etaLow };
1019 Double_t binZeroStudyXmax[nBinsBinZeroStudy] = { binsCent[nCentBins], binsPt[nPtBins], etaUp };
1021 fChargedGenPrimariesTriggerSel = new THnSparseD("fChargedGenPrimariesTriggerSel", "Trigger sel.", nBinsBinZeroStudy, binZeroStudyBins,
1022 binZeroStudyXmin, binZeroStudyXmax);
1023 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSel, binsCent, binsPt);
1024 fOutputContainer->Add(fChargedGenPrimariesTriggerSel);
1026 fChargedGenPrimariesTriggerSelVtxCut = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCut", "Vertex cut", nBinsBinZeroStudy,
1027 binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1028 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCut, binsCent, binsPt);
1029 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCut);
1031 fChargedGenPrimariesTriggerSelVtxCutZ = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCutZ", "Vertex #it{z} cut", nBinsBinZeroStudy,
1032 binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1033 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCutZ, binsCent, binsPt);
1034 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCutZ);
1036 fChargedGenPrimariesTriggerSelVtxCutZPileUpRej = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCutZPileUpRej", "Vertex #it{z} cut",
1037 nBinsBinZeroStudy, binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1038 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCutZPileUpRej, binsCent, binsPt);
1039 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCutZPileUpRej);
1043 printf("File: %s, Line: %d: UserCreateOutputObjects -> Posting output data\n", (char*)__FILE__, __LINE__);
1045 PostData(1, fOutputContainer);
1047 PostData(2, fContainerEff);
1048 if (fDoDeDxCheck || fDoPtResolution)
1049 PostData(3, fQAContainer);
1052 printf("File: %s, Line: %d: UserCreateOutputObjects -> Done\n", (char*)__FILE__, __LINE__);
1056 //________________________________________________________________________
1057 void AliAnalysisTaskPID::UserExec(Option_t *)
1060 // Called for each event
1063 printf("File: %s, Line: %d: UserExec\n", (char*)__FILE__, __LINE__);
1065 // No processing of event, if input is fed in directly from another task
1066 if (fInputFromOtherTask)
1070 printf("File: %s, Line: %d: UserExec -> Processing started\n", (char*)__FILE__, __LINE__);
1072 fEvent = dynamic_cast<AliVEvent*>(InputEvent());
1074 Printf("ERROR: fEvent not available");
1078 ConfigureTaskForCurrentEvent(fEvent);
1080 fMC = dynamic_cast<AliMCEvent*>(MCEvent());
1082 if (!fPIDResponse || !fPIDcombined)
1085 Double_t centralityPercentile = -1;
1086 if (fStoreCentralityPercentile) {
1087 if (fCentralityEstimator.Contains("ITSTPCtracklets", TString::kIgnoreCase)) {
1088 // Special pp centrality estimator
1089 AliESDEvent* esdEvent = dynamic_cast<AliESDEvent*>(fEvent);
1091 AliError("Not esd event -> Cannot use tracklet multiplicity estimator!");
1092 centralityPercentile = -1;
1095 centralityPercentile = AliESDtrackCuts::GetReferenceMultiplicity(esdEvent, AliESDtrackCuts::kTrackletsITSTPC, fEtaAbsCutUp);
1097 else if (fCentralityEstimator.Contains("ppMult", TString::kIgnoreCase)) {
1098 // Another special pp centrality estimator
1099 centralityPercentile = fAnaUtils->GetMultiplicityPercentile(fEvent, GetPPCentralityEstimator().Data());
1102 // Ordinary centrality estimator
1103 centralityPercentile = fEvent->GetCentrality()->GetCentralityPercentile(fCentralityEstimator.Data());
1107 // Check if vertex is ok, but don't apply cut on z position
1108 const Bool_t passedVertexSelection = GetVertexIsOk(fEvent, kFALSE);
1109 // Now check again, but also require z position to be in desired range
1110 const Bool_t passedVertexZSelection = GetVertexIsOk(fEvent, kTRUE);
1112 const Bool_t isPileUp = GetIsPileUp(fEvent, fPileUpRejectionType);
1116 if (fDoBinZeroStudy && fMC) {
1117 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1118 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1123 if (!fMC->IsPhysicalPrimary(iPart))
1126 const Double_t etaGen = mcPart->Eta();
1127 const Double_t ptGen = mcPart->Pt();
1129 Double_t values[kBinZeroStudyNumAxes] = { 0. };
1130 values[kBinZeroStudyCentrality] = centralityPercentile;
1131 values[kBinZeroStudyGenPt] = ptGen;
1132 values[kBinZeroStudyGenEta] = etaGen;
1134 fChargedGenPrimariesTriggerSel->Fill(values);
1135 if (passedVertexSelection) {
1136 fChargedGenPrimariesTriggerSelVtxCut->Fill(values);
1137 if (passedVertexZSelection) {
1138 fChargedGenPrimariesTriggerSelVtxCutZ->Fill(values);
1140 fChargedGenPrimariesTriggerSelVtxCutZPileUpRej->Fill(values);
1149 // Event counters for trigger selection, vertex cuts and pile-up rejection
1150 IncrementEventCounter(centralityPercentile, kTriggerSel);
1152 if (!passedVertexSelection)
1155 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCut);
1157 if (!passedVertexZSelection)
1160 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCutNoPileUpRejection);
1161 // ATTENTION: Is this the right place for the pile-up rejection? Important to have still the proper bin-0 correction,
1162 // which is done solely with sel and selVtx, since the zvtx selection does ~not change the spectra. The question is whether the pile-up
1163 // rejection changes the spectra. If not, then it is perfectly fine to put it here and keep the usual histo for the normalisation to number
1164 // of events. But if it does change the spectra, this must somehow be corrected for.
1165 // NOTE: multiplicity >= 0 usually implies a properly reconstructed vertex. Hence, the bin-0 correction cannot be done in multiplicity bins.
1166 // Furthermore, there seems to be no MC simulation with pile-up rejection, so the bin-0 correction cannot be extracted with it. Pile-up
1167 // rejection has only a minor impact, so maybe there is no need to dig further.
1171 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCut);
1173 Double_t magField = fEvent->GetMagneticField();
1176 if (fDoPID || fDoEfficiency) {
1177 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1178 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1183 // Define clean MC sample with corresponding particle level track cuts:
1184 // - MC-track must be in desired eta range
1185 // - MC-track must be physical primary
1186 // - Species must be one of those in question (everything else goes to the overflow bin of mcID)
1188 // Geometrie should be the same as on the reconstructed level -> By definition analysis within this eta interval
1189 if (!IsInAcceptedEtaRange(TMath::Abs(mcPart->Eta()))) continue;
1191 Int_t mcID = PDGtoMCID(mcPart->PdgCode());
1193 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1194 Double_t chargeMC = mcPart->Charge() / 3.;
1196 if (TMath::Abs(chargeMC) < 0.01)
1197 continue; // Reject neutral particles (only relevant, if mcID is not used)
1199 if (!fMC->IsPhysicalPrimary(iPart))
1203 Double_t valuesGenYield[kGenYieldNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), centralityPercentile, -1, -1, -1, -1 };
1204 valuesGenYield[GetIndexOfChargeAxisGenYield()] = chargeMC;
1206 fhMCgeneratedYieldsPrimaries->Fill(valuesGenYield);
1210 if (fDoEfficiency) {
1211 Double_t valueEff[kEffNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), mcPart->Eta(), chargeMC, centralityPercentile,
1214 fContainerEff->Fill(valueEff, kStepGenWithGenCuts);
1220 // Track loop to fill a Train spectrum
1221 for (Int_t iTracks = 0; iTracks < fEvent->GetNumberOfTracks(); iTracks++) {
1222 AliVTrack* track = dynamic_cast<AliVTrack*>(fEvent->GetTrack(iTracks));
1224 Printf("ERROR: Could not retrieve track %d", iTracks);
1229 // Apply detector level track cuts
1230 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
1231 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
1232 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
1236 if(fTrackFilter && !fTrackFilter->IsSelected(track))
1239 if (GetUseTPCCutMIGeo()) {
1240 if (!TPCCutMIGeo(track, fEvent))
1243 else if (GetUseTPCnclCut()) {
1244 if (!TPCnclCut(track))
1249 if (!PhiPrimeCut(track, magField))
1250 continue; // reject track
1253 Int_t pdg = 0; // = 0 indicates data for the moment
1254 AliMCParticle* mcTrack = 0x0;
1255 Int_t mcID = AliPID::kUnknown;
1259 label = track->GetLabel();
1264 mcTrack = dynamic_cast<AliMCParticle*>(fMC->GetTrack(TMath::Abs(label)));
1266 Printf("ERROR: Could not retrieve mcTrack with label %d for track %d", label, iTracks);
1270 pdg = mcTrack->PdgCode();
1271 mcID = PDGtoMCID(mcTrack->PdgCode());
1273 if (fDoEfficiency) {
1274 // For efficiency: Reconstructed track has survived all cuts on the detector level (excluding acceptance)
1275 // and has an associated MC track which is a physical primary and was generated inside the acceptance
1276 if (fMC->IsPhysicalPrimary(TMath::Abs(label)) &&
1277 IsInAcceptedEtaRange(TMath::Abs(mcTrack->Eta()))) {
1279 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1280 Double_t value[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3., centralityPercentile,
1282 fContainerEff->Fill(value, kStepRecWithGenCuts);
1284 Double_t valueMeas[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1286 fContainerEff->Fill(valueMeas, kStepRecWithGenCutsMeasuredObs);
1291 // Only process tracks inside the desired eta window
1292 if (!IsInAcceptedEtaRange(TMath::Abs(track->Eta()))) continue;
1294 if (fDoPID || fDoDeDxCheck || fDoPtResolution)
1295 ProcessTrack(track, pdg, centralityPercentile, -1); // No jet information in this case -> Set jet pT to -1
1297 if (fDoPtResolution) {
1298 if (mcTrack && fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1299 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1300 Double_t valuePtRes[kPtResNumAxes] = { -1, mcTrack->Pt(), track->Pt(), mcTrack->Charge() / 3., centralityPercentile };
1301 FillPtResolution(mcID, valuePtRes);
1305 if (fDoEfficiency) {
1307 Double_t valueRecAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1309 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObs);
1311 Double_t weight = IsSecondaryWithStrangeMotherMC(fMC, TMath::Abs(label)) ?
1312 GetMCStrangenessFactorCMS(fMC, mcTrack) : 1.0;
1313 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsStrangenessScaled, weight);
1315 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1316 Double_t valueGenAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3.,
1317 centralityPercentile, -1, -1, -1 };
1318 if (fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1319 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsPrimaries);
1320 fContainerEff->Fill(valueGenAllCuts, kStepRecWithRecCutsPrimaries);
1327 printf("File: %s, Line: %d: UserExec -> Processing done\n", (char*)__FILE__, __LINE__);
1332 printf("File: %s, Line: %d: UserExec -> Done\n", (char*)__FILE__, __LINE__);
1335 //________________________________________________________________________
1336 void AliAnalysisTaskPID::Terminate(const Option_t *)
1338 // Draw result to the screen
1339 // Called once at the end of the query
1343 //_____________________________________________________________________________
1344 void AliAnalysisTaskPID::CheckDoAnyStematicStudiesOnTheExpectedSignal()
1346 // Check whether at least one scale factor indicates the ussage of systematic studies
1347 // and set internal flag accordingly.
1349 fDoAnySystematicStudiesOnTheExpectedSignal = kFALSE;
1352 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
1353 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
1354 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1358 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1359 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1360 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1364 if ((TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
1365 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon)) {
1366 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1370 if (TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
1371 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1377 //_____________________________________________________________________________
1378 void AliAnalysisTaskPID::ConfigureTaskForCurrentEvent(AliVEvent* event)
1380 // Configure the task for the current event. In particular, this is needed if the run number changes
1383 AliError("Could not set up task: no event!");
1387 Int_t run = event->GetRunNumber();
1390 // If systematics on eta is investigated, need to calculate the maxEtaVariationMap
1391 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1392 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1393 if (!CalculateMaxEtaVariationMapFromPIDResponse())
1394 AliFatal("Systematics on eta correction requested, but failed to calculate max eta varation map!");
1402 //_____________________________________________________________________________
1403 Int_t AliAnalysisTaskPID::PDGtoMCID(Int_t pdg)
1405 // Returns the corresponding AliPID index to the given pdg code.
1406 // Returns AliPID::kUnkown if pdg belongs to a not considered species.
1408 Int_t absPDGcode = TMath::Abs(pdg);
1409 if (absPDGcode == 211) {//Pion
1410 return AliPID::kPion;
1412 else if (absPDGcode == 321) {//Kaon
1413 return AliPID::kKaon;
1415 else if (absPDGcode == 2212) {//Proton
1416 return AliPID::kProton;
1418 else if (absPDGcode == 11) {//Electron
1419 return AliPID::kElectron;
1421 else if (absPDGcode == 13) {//Muon
1422 return AliPID::kMuon;
1425 return AliPID::kUnknown;
1429 //_____________________________________________________________________________
1430 void AliAnalysisTaskPID::GetJetTrackObservables(Double_t trackPt, Double_t jetPt, Double_t& z, Double_t& xi)
1432 // Uses trackPt and jetPt to obtain z and xi.
1434 z = (jetPt > 0 && trackPt >= 0) ? (trackPt / jetPt) : -1;
1435 xi = (z > 0) ? TMath::Log(1. / z) : -1;
1437 if(trackPt > (1. - 1e-06) * jetPt && trackPt < (1. + 1e-06) * jetPt) { // case z=1 : move entry to last histo bin <1
1444 //_____________________________________________________________________________
1445 void AliAnalysisTaskPID::CleanupParticleFractionHistos()
1447 // Delete histos with particle fractions
1449 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1450 delete fFractionHists[i];
1451 fFractionHists[i] = 0x0;
1453 delete fFractionSysErrorHists[i];
1454 fFractionSysErrorHists[i] = 0x0;
1459 //_____________________________________________________________________________
1460 Double_t AliAnalysisTaskPID::ConvolutedGaus(const Double_t* xx, const Double_t* par) const
1462 // Convolutes gauss with an exponential tail which describes dEdx-response better than pure gaussian
1464 const Double_t mean = par[0];
1465 const Double_t sigma = par[1];
1466 const Double_t lambda = par[2];
1469 printf("File: %s, Line: %d: ConvolutedGaus: mean %e, sigma %e, lambda %e\n", (char*)__FILE__, __LINE__, mean, sigma, lambda);
1471 return lambda/sigma*TMath::Exp(-lambda/sigma*(xx[0]-mean)+lambda*lambda*0.5)*0.5*TMath::Erfc((-xx[0]+mean+sigma*lambda)/sigma*fgkOneOverSqrt2);
1475 //_____________________________________________________________________________
1476 inline Double_t AliAnalysisTaskPID::FastGaus(Double_t x, Double_t mean, Double_t sigma) const
1478 // Calculate an unnormalised gaussian function with mean and sigma.
1480 if (sigma < fgkEpsilon)
1483 const Double_t arg = (x - mean) / sigma;
1484 return exp(-0.5 * arg * arg);
1488 //_____________________________________________________________________________
1489 inline Double_t AliAnalysisTaskPID::FastNormalisedGaus(Double_t x, Double_t mean, Double_t sigma) const
1491 // Calculate a normalised (divided by sqrt(2*Pi)*sigma) gaussian function with mean and sigma.
1493 if (sigma < fgkEpsilon)
1496 const Double_t arg = (x - mean) / sigma;
1497 const Double_t res = exp(-0.5 * arg * arg);
1498 return res / (2.50662827463100024 * sigma); //sqrt(2*Pi)=2.50662827463100024
1502 //_____________________________________________________________________________
1503 Int_t AliAnalysisTaskPID::FindBinWithinRange(TAxis* axis, Double_t value) const
1505 // Find the corresponding bin of the axis. Values outside the range (also under and overflow) will be set to the first/last
1508 Int_t bin = axis->FindFixBin(value);
1512 if (bin > axis->GetNbins())
1513 bin = axis->GetNbins();
1519 //_____________________________________________________________________________
1520 Int_t AliAnalysisTaskPID::FindFirstBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1523 // Kind of projects a TH3 to 1 bin combination in y and z
1524 // and looks for the first x bin above a threshold for this projection.
1525 // If no such bin is found, -1 is returned.
1530 Int_t nBinsX = hist->GetNbinsX();
1531 for (Int_t xBin = 1; xBin <= nBinsX; xBin++) {
1532 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1540 //_____________________________________________________________________________
1541 Int_t AliAnalysisTaskPID::FindLastBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1544 // Kind of projects a TH3 to 1 bin combination in y and z
1545 // and looks for the last x bin above a threshold for this projection.
1546 // If no such bin is found, -1 is returned.
1551 Int_t nBinsX = hist->GetNbinsX();
1552 for (Int_t xBin = nBinsX; xBin >= 1; xBin--) {
1553 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1561 //_____________________________________________________________________________
1562 Bool_t AliAnalysisTaskPID::GetParticleFraction(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1563 AliPID::EParticleType species,
1564 Double_t& fraction, Double_t& fractionErrorStat, Double_t& fractionErrorSys) const
1566 // Computes the particle fraction for the corresponding species for the given trackPt, jetPt and centrality.
1567 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1568 // On success (return value kTRUE), fraction contains the particle fraction, fractionErrorStat(Sys) the sigma of its
1569 // statistical (systematic) error
1572 fractionErrorStat = 999.;
1573 fractionErrorSys = 999.;
1575 if (species > AliPID::kProton || species < AliPID::kElectron) {
1576 AliError(Form("Only fractions for species index %d to %d availabe, but not for the requested one: %d", 0, AliPID::kProton, species));
1580 if (!fFractionHists[species]) {
1581 AliError(Form("Histo with particle fractions for species %d not loaded!", species));
1586 Int_t jetPtBin = FindBinWithinRange(fFractionHists[species]->GetYaxis(), jetPt);
1587 Int_t centBin = FindBinWithinRange(fFractionHists[species]->GetZaxis(), centralityPercentile);
1589 // The following interpolation takes the bin content of the first/last available bin,
1590 // if requested point lies beyond bin center of first/last bin.
1591 // The interpolation is only done for the x-axis (track pT), i.e. jetPtBin and centBin are fix,
1592 // because the analysis will anyhow be run in bins of jetPt and centrality and
1593 // it is not desired to correlate different jetPt bins via interpolation.
1595 // The same procedure is used for the error of the fraction
1596 TAxis* xAxis = fFractionHists[species]->GetXaxis();
1598 // No interpolation to values beyond the centers of the first/last bins (we don't know exactly where the spectra start or stop,
1599 // thus, search for the first and last bin above 0.0 to constrain the range
1600 Int_t firstBin = TMath::Max(1, FindFirstBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1601 Int_t lastBin = TMath::Min(fFractionHists[species]->GetNbinsX(),
1602 FindLastBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1604 if (trackPt <= xAxis->GetBinCenter(firstBin)) {
1605 fraction = fFractionHists[species]->GetBinContent(firstBin, jetPtBin, centBin);
1606 fractionErrorStat = fFractionHists[species]->GetBinError(firstBin, jetPtBin, centBin);
1607 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(firstBin, jetPtBin, centBin) : 0.;
1609 else if (trackPt >= xAxis->GetBinCenter(lastBin)) {
1610 fraction = fFractionHists[species]->GetBinContent(lastBin, jetPtBin, centBin);
1611 fractionErrorStat = fFractionHists[species]->GetBinError(lastBin, jetPtBin, centBin);
1612 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(lastBin, jetPtBin, centBin) : 0.;
1615 Double_t x0 = 0., x1 = 0., y0 = 0., y1 = 0.;
1616 Double_t y0errStat = 0., y1errStat = 0., y0errSys = 0., y1errSys = 0.;
1617 Int_t trackPtBin = xAxis->FindFixBin(trackPt);
1619 // Linear interpolation between nearest neighbours in trackPt
1620 if (trackPt <= xAxis->GetBinCenter(trackPtBin)) {
1621 y0 = fFractionHists[species]->GetBinContent(trackPtBin - 1, jetPtBin, centBin);
1622 y0errStat = fFractionHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin);
1623 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin)
1625 x0 = xAxis->GetBinCenter(trackPtBin - 1);
1626 y1 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1627 y1errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1628 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1630 x1 = xAxis->GetBinCenter(trackPtBin);
1633 y0 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1634 y0errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1635 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1637 x0 = xAxis->GetBinCenter(trackPtBin);
1638 y1 = fFractionHists[species]->GetBinContent(trackPtBin + 1, jetPtBin, centBin);
1639 y1errStat = fFractionHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin);
1640 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin)
1642 x1 = xAxis->GetBinCenter(trackPtBin + 1);
1645 // Per construction: x0 < trackPt < x1
1646 fraction = y0 + (trackPt - x0) * ((y1 - y0) / (x1 - x0));
1647 fractionErrorStat = y0errStat + (trackPt - x0) * ((y1errStat - y0errStat) / (x1 - x0));
1648 fractionErrorSys = fFractionSysErrorHists[species] ? (y0errSys + (trackPt - x0) * ((y1errSys - y0errSys) / (x1 - x0))) : 0.;
1655 //_____________________________________________________________________________
1656 Bool_t AliAnalysisTaskPID::GetParticleFractions(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1657 Double_t* prob, Int_t smearSpeciesByError,
1658 Int_t takeIntoAccountSpeciesSysError, Bool_t uniformSystematicError) const
1660 // Fills the particle fractions for the given trackPt, jetPt and centrality into "prob".
1661 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1662 // If smearSpeciesByError is >= 0 && < AliPID::kSPECIES, the returned fractions will be a random number distributed
1663 // with a gauss with mean being the corresponding particle fraction and sigma it's error for the considered species
1664 // "smearSpeciesByError".
1665 // Note that in this case the fractions for all species will NOT sum up to 1!
1666 // Thus, all other species fractions will be re-scaled weighted with their corresponding statistical error.
1667 // A similar procedure is used for "takeIntoAccountSpeciesSysError": The systematic error of the corresponding species
1668 // is used to generate a random number with uniform distribution in [mean - sysError, mean + sysError] for the new mean
1669 // (in cace of uniformSystematicError = kTRUE, otherwise it will be a gaus(mean, sysError)),
1670 // then the other species will be re-scaled according to their systematic errors.
1671 // First, the systematic error uncertainty procedure will be performed (that is including re-scaling), then the statistical
1672 // uncertainty procedure.
1673 // On success, kTRUE is returned.
1675 if (!prob || smearSpeciesByError >= AliPID::kSPECIES || takeIntoAccountSpeciesSysError >= AliPID::kSPECIES)
1678 Double_t probTemp[AliPID::kSPECIES];
1679 Double_t probErrorStat[AliPID::kSPECIES];
1680 Double_t probErrorSys[AliPID::kSPECIES];
1682 Bool_t success = kTRUE;
1683 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kElectron,
1684 probTemp[AliPID::kElectron], probErrorStat[AliPID::kElectron],
1685 probErrorSys[AliPID::kElectron]);
1686 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kMuon,
1687 probTemp[AliPID::kMuon], probErrorStat[AliPID::kMuon], probErrorSys[AliPID::kMuon]);
1688 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kPion,
1689 probTemp[AliPID::kPion], probErrorStat[AliPID::kPion], probErrorSys[AliPID::kPion]);
1690 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kKaon,
1691 probTemp[AliPID::kKaon], probErrorStat[AliPID::kKaon], probErrorSys[AliPID::kKaon]);
1692 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kProton,
1693 probTemp[AliPID::kProton], probErrorStat[AliPID::kProton], probErrorSys[AliPID::kProton]);
1698 // If desired, take into account the systematic error of the corresponding species and re-generate probTemp accordingly
1699 if (takeIntoAccountSpeciesSysError >= 0) {
1700 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1701 Double_t generatedFraction = uniformSystematicError
1702 ? fRandom->Rndm() * 2. * probErrorSys[takeIntoAccountSpeciesSysError]
1703 - probErrorSys[takeIntoAccountSpeciesSysError]
1704 + probTemp[takeIntoAccountSpeciesSysError]
1705 : fRandom->Gaus(probTemp[takeIntoAccountSpeciesSysError],
1706 probErrorSys[takeIntoAccountSpeciesSysError]);
1708 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1709 if (generatedFraction < 0.)
1710 generatedFraction = 0.;
1711 else if (generatedFraction > 1.)
1712 generatedFraction = 1.;
1714 // Calculate difference from original fraction (original fractions sum up to 1!)
1715 Double_t deltaFraction = generatedFraction - probTemp[takeIntoAccountSpeciesSysError];
1717 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1718 if (deltaFraction > 0) {
1719 // Some part will be SUBTRACTED from the other fractions
1720 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1721 if (probTemp[i] - probErrorSys[i] < 0)
1722 probErrorSys[i] = probTemp[i];
1726 // Some part will be ADDED to the other fractions
1727 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1728 if (probTemp[i] + probErrorSys[i] > 1)
1729 probErrorSys[i] = 1. - probTemp[i];
1733 // Compute summed weight of all fractions except for the considered one
1734 Double_t summedWeight = 0.;
1735 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1736 if (i != takeIntoAccountSpeciesSysError)
1737 summedWeight += probErrorSys[i];
1740 // Compute the weight for the other species
1742 if (summedWeight <= 1e-13) {
1743 // If this happens for some reason (it should not!), just assume flat weight
1744 printf("Error: summedWeight (sys error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1745 trackPt, jetPt, centralityPercentile);
1748 Double_t weight[AliPID::kSPECIES];
1749 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1750 if (i != takeIntoAccountSpeciesSysError) {
1751 if (summedWeight > 1e-13)
1752 weight[i] = probErrorSys[i] / summedWeight;
1754 weight[i] = probErrorSys[i] / (AliPID::kSPECIES - 1);
1758 // For the final generated fractions, set the generated value for the considered species
1759 // and the generated value minus delta times statistical weight
1760 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1761 if (i != takeIntoAccountSpeciesSysError)
1762 probTemp[i] = probTemp[i] - weight[i] * deltaFraction;
1764 probTemp[i] = generatedFraction;
1768 // Using the values of probTemp (either the original ones or those after taking into account the systematic error),
1769 // calculate the final fractions - if the statistical error is to be taken into account, smear the corresponding
1770 // fraction. If not, just write probTemp to the final result array.
1771 if (smearSpeciesByError >= 0) {
1772 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1773 Double_t generatedFraction = fRandom->Gaus(probTemp[smearSpeciesByError], probErrorStat[smearSpeciesByError]);
1775 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1776 if (generatedFraction < 0.)
1777 generatedFraction = 0.;
1778 else if (generatedFraction > 1.)
1779 generatedFraction = 1.;
1781 // Calculate difference from original fraction (original fractions sum up to 1!)
1782 Double_t deltaFraction = generatedFraction - probTemp[smearSpeciesByError];
1784 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1785 if (deltaFraction > 0) {
1786 // Some part will be SUBTRACTED from the other fractions
1787 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1788 if (probTemp[i] - probErrorStat[i] < 0)
1789 probErrorStat[i] = probTemp[i];
1793 // Some part will be ADDED to the other fractions
1794 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1795 if (probTemp[i] + probErrorStat[i] > 1)
1796 probErrorStat[i] = 1. - probTemp[i];
1800 // Compute summed weight of all fractions except for the considered one
1801 Double_t summedWeight = 0.;
1802 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1803 if (i != smearSpeciesByError)
1804 summedWeight += probErrorStat[i];
1807 // Compute the weight for the other species
1809 if (summedWeight <= 1e-13) {
1810 // If this happens for some reason (it should not!), just assume flat weight
1811 printf("Error: summedWeight (stat error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1812 trackPt, jetPt, centralityPercentile);
1815 Double_t weight[AliPID::kSPECIES];
1816 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1817 if (i != smearSpeciesByError) {
1818 if (summedWeight > 1e-13)
1819 weight[i] = probErrorStat[i] / summedWeight;
1821 weight[i] = probErrorStat[i] / (AliPID::kSPECIES - 1);
1825 // For the final generated fractions, set the generated value for the considered species
1826 // and the generated value minus delta times statistical weight
1827 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1828 if (i != smearSpeciesByError)
1829 prob[i] = probTemp[i] - weight[i] * deltaFraction;
1831 prob[i] = generatedFraction;
1835 // Just take the generated values
1836 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
1837 prob[i] = probTemp[i];
1841 // Should already be normalised, but make sure that it really is:
1842 Double_t probSum = 0.;
1843 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1850 if (TMath::Abs(probSum - 1.0) > 1e-4) {
1851 printf("Warning: Re-normalising sum of fractions: Sum is %e\n", probSum);
1852 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1861 //_____________________________________________________________________________
1862 const TH3D* AliAnalysisTaskPID::GetParticleFractionHisto(Int_t species, Bool_t sysError) const
1864 if (species < AliPID::kElectron || species > AliPID::kProton)
1867 return sysError ? fFractionSysErrorHists[species] : fFractionHists[species];
1871 //_____________________________________________________________________________
1872 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(Int_t motherPDG, Double_t motherGenPt)
1874 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1875 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction, which uses
1876 // the following data from CMS pp @ 7 TeV inclusive (JHEP 05 (2011) 064)
1880 const Int_t absMotherPDG = TMath::Abs(motherPDG);
1882 if (absMotherPDG == 310 || absMotherPDG == 321) { // K0s / K+ / K-
1883 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.768049;
1884 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.732933;
1885 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.650298;
1886 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.571332;
1887 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.518734;
1888 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.492543;
1889 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.482704;
1890 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.488056;
1891 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.488861;
1892 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.492862;
1893 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.504332;
1894 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.501858;
1895 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.512970;
1896 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.524131;
1897 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.539130;
1898 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.554101;
1899 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.560348;
1900 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.568869;
1901 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.583310;
1902 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.604818;
1903 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.632630;
1904 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.710070;
1905 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.736365;
1906 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 0.835865;
1909 if (absMotherPDG == 3122) { // Lambda
1910 //if (absMotherPDG == 3122 || absMotherPDG == 3112 || absMotherPDG == 3222) { // Lambda / Sigma- / Sigma+
1911 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.645162;
1912 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.627431;
1913 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.457136;
1914 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.384369;
1915 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.330597;
1916 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.309571;
1917 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.293620;
1918 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.283709;
1919 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.282047;
1920 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.277261;
1921 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.275772;
1922 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.280726;
1923 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.288540;
1924 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.288315;
1925 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.296619;
1926 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.302993;
1927 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.338121;
1928 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.349800;
1929 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.356802;
1930 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.391202;
1931 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.422573;
1932 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.573815;
1933 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.786984;
1934 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 1.020021;
1937 if (absMotherPDG == 3312 || absMotherPDG == 3322) { // xi
1938 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.666620;
1939 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.575908;
1940 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.433198;
1941 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.340901;
1942 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.290896;
1943 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.236074;
1944 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.218681;
1945 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.207763;
1946 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.222848;
1947 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.208806;
1948 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.197275;
1949 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.183645;
1950 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.188788;
1951 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.188282;
1952 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.207442;
1953 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.240388;
1954 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.241916;
1955 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.208276;
1956 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.234550;
1957 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.251689;
1958 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.310204;
1959 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.343492;
1962 const Double_t weight = 1. / fac;
1968 //_____________________________________________________________________________
1969 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(AliMCEvent* mcEvent, AliMCParticle* daughter)
1971 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1972 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction
1977 AliMCParticle* currentMother = daughter;
1978 AliMCParticle* currentDaughter = daughter;
1981 // find first primary mother K0s, Lambda or Xi
1983 Int_t daughterPDG = currentDaughter->PdgCode();
1985 Int_t motherLabel = currentDaughter->GetMother();
1986 if(motherLabel >= mcEvent->GetNumberOfTracks()){ // protection
1987 currentMother = currentDaughter;
1991 currentMother = (AliMCParticle*)mcEvent->GetTrack(motherLabel);
1993 if (!currentMother) {
1994 currentMother = currentDaughter;
1998 Int_t motherPDG = currentMother->PdgCode();
2000 // phys. primary found ?
2001 if (mcEvent->IsPhysicalPrimary(motherLabel))
2004 if (TMath::Abs(daughterPDG) == 321) {
2005 // K+/K- e.g. from phi (ref data not feeddown corrected)
2006 currentMother = currentDaughter;
2009 if (TMath::Abs(motherPDG) == 310) {
2010 // K0s e.g. from phi (ref data not feeddown corrected)
2013 if (TMath::Abs(motherPDG) == 3212 && TMath::Abs(daughterPDG) == 3122) {
2014 // Mother Sigma0, daughter Lambda (this case not included in feeddown corr.)
2015 currentMother = currentDaughter;
2019 currentDaughter = currentMother;
2023 Int_t motherPDG = currentMother->PdgCode();
2024 Double_t motherGenPt = currentMother->Pt();
2026 return GetMCStrangenessFactorCMS(motherPDG, motherGenPt);
2030 // _________________________________________________________________________________
2031 AliAnalysisTaskPID::TOFpidInfo AliAnalysisTaskPID::GetTOFType(const AliVTrack* track, Int_t tofMode) const
2033 // Get the (locally defined) particle type judged by TOF
2035 if (!fPIDResponse) {
2036 Printf("ERROR: fPIDResponse not available -> Cannot determine TOF type!");
2040 /*TODO still needs some further thinking how to implement it....
2041 // TOF PID status (kTOFout, kTIME) automatically checked by return value of ComputeTPCProbability;
2042 // also, probability array will be set there (no need to initialise here)
2043 Double_t p[AliPID::kSPECIES];
2044 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->ComputeTPCProbability(track, AliPID::kSPECIES, p);
2045 if (tofStatus != AliPIDResponse::kDetPidOk)
2048 // Do not consider muons
2049 p[AliPID::kMuon] = 0.;
2051 // Probabilities are not normalised yet
2053 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2059 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2062 Double_t probThreshold = -999.;
2064 // If there is only one distribution, the threshold corresponds to...
2068 else if (tofMode == 1) { // default
2069 probThreshold = 0.9973; // a 3-sigma inclusion cut
2071 else if (tofMode == 2) {
2076 Printf("ERROR: Bad TOF mode: %d!", tofMode);
2082 ///* OLD: cut with n-sigmas (ATTENTION: Does not take into account properly the TOF tail!)
2083 // Check kTOFout, kTIME, mismatch
2084 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->CheckPIDStatus(AliPIDResponse::kTOF, track);
2085 if (tofStatus != AliPIDResponse::kDetPidOk)
2088 Double_t nsigma[kNumTOFspecies + 1] = { -999., -999., -999., -999. };
2089 nsigma[kTOFpion] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kPion);
2090 nsigma[kTOFkaon] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kKaon);
2091 nsigma[kTOFproton] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton);
2093 Double_t inclusion = -999;
2094 Double_t exclusion = -999;
2100 else if (tofMode == 1) { // default
2104 else if (tofMode == 2) {
2109 Printf("ERROR: Bad TOF mode: %d!", tofMode);
2113 // Do not cut on nSigma electron because this would also remove pions in a large pT range.
2114 // The electron contamination of the pion sample can be treated by TPC dEdx fits afterwards.
2115 if (TMath::Abs(nsigma[kTOFpion]) < inclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
2117 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) < inclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
2119 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) < inclusion)
2123 // There are no TOF electrons selected because the purity is rather bad, even for small momenta
2124 // (also a small mismatch probability significantly affects electrons because their fraction
2125 // is small). There is no need for TOF electrons anyway, since the dEdx distribution of kaons and
2126 // protons in a given pT bin (also at the dEdx crossings) is very different from that of electrons.
2127 // This is due to the steeply falling dEdx of p and K with momentum, whereas the electron dEdx stays
2129 // As a result, the TPC fit yields a more accurate electron fraction than the TOF selection can do.
2135 // _________________________________________________________________________________
2136 Bool_t AliAnalysisTaskPID::IsSecondaryWithStrangeMotherMC(AliMCEvent* mcEvent, Int_t partLabel)
2138 // Check whether particle is a secondary with strange mother, i.e. returns kTRUE if a strange mother is found
2139 // and the particle is NOT a physical primary. In all other cases kFALSE is returned
2141 if (!mcEvent || partLabel < 0)
2144 AliMCParticle* part = (AliMCParticle*)mcEvent->GetTrack(partLabel);
2149 if (mcEvent->IsPhysicalPrimary(partLabel))
2152 Int_t iMother = part->GetMother();
2157 AliMCParticle* partM = (AliMCParticle*)mcEvent->GetTrack(iMother);
2161 Int_t codeM = TMath::Abs(partM->PdgCode());
2162 Int_t mfl = Int_t(codeM / TMath::Power(10, Int_t(TMath::Log10(codeM))));
2163 if (mfl == 3 && codeM != 3) // codeM = 3 is for s quark
2170 //_____________________________________________________________________________
2171 Bool_t AliAnalysisTaskPID::SetParticleFractionHisto(const TH3D* hist, Int_t species, Bool_t sysError)
2173 // Store a clone of hist (containing the particle fractions of the corresponding species with statistical error (sysError = kFALSE)
2174 // or systematic error (sysError = kTRUE), respectively), internally
2176 if (species < AliPID::kElectron || species > AliPID::kProton) {
2177 AliError(Form("Only fractions for species index %d to %d can be set, but not for the requested one: %d", 0,
2178 AliPID::kProton, species));
2183 delete fFractionSysErrorHists[species];
2185 fFractionSysErrorHists[species] = new TH3D(*hist);
2188 delete fFractionHists[species];
2190 fFractionHists[species] = new TH3D(*hist);
2197 //_____________________________________________________________________________
2198 Bool_t AliAnalysisTaskPID::SetParticleFractionHistosFromFile(const TString filePathName, Bool_t sysError)
2200 // Loads particle fractions for all species from the desired file and returns kTRUE on success.
2201 // The maps are assumed to be of Type TH3D, to sit in the main directory and to have names
2202 // Form("hFraction_%e", AliPID::ParticleName(i)) for sysError = kFALSE and
2203 // Form("hFractionSysError_%e", AliPID::ParticleName(i)) for sysError = kTRUE.
2205 TFile* f = TFile::Open(filePathName.Data());
2207 std::cout << "Failed to open file with particle fractions \"" << filePathName.Data() << "\"!" << std::endl;
2212 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
2213 TString histName = Form("hFraction%s_%s", sysError ? "SysError" : "", AliPID::ParticleName(i));
2214 hist = dynamic_cast<TH3D*>(f->Get(histName.Data()));
2216 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2217 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2218 CleanupParticleFractionHistos();
2222 if (!SetParticleFractionHisto(hist, i, sysError)) {
2223 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2224 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2225 CleanupParticleFractionHistos();
2237 //_____________________________________________________________________________
2238 Double_t AliAnalysisTaskPID::GetMaxEtaVariation(Double_t dEdxSplines)
2240 // Returns the maximum eta variation (i.e. deviation of eta correction factor from unity) for the
2241 // given (spline) dEdx
2243 if (dEdxSplines < 1. || !fhMaxEtaVariation) {
2244 Printf("Error GetMaxEtaVariation: No map or invalid dEdxSplines (%f)!", dEdxSplines);
2248 Int_t bin = fhMaxEtaVariation->GetXaxis()->FindFixBin(1. / dEdxSplines);
2252 if (bin > fhMaxEtaVariation->GetXaxis()->GetNbins())
2253 bin = fhMaxEtaVariation->GetXaxis()->GetNbins();
2255 return fhMaxEtaVariation->GetBinContent(bin);
2259 //_____________________________________________________________________________
2260 Int_t AliAnalysisTaskPID::GetRandomParticleTypeAccordingToParticleFractions(Double_t trackPt, Double_t jetPt,
2261 Double_t centralityPercentile,
2262 Bool_t smearByError,
2263 Bool_t takeIntoAccountSysError) const
2265 // Uses the stored histograms with the particle fractions to generate a random particle type according to these fractions.
2266 // In case of problems (e.g. histo missing), AliPID::kUnknown is returned.
2267 // If smearByError is kTRUE, the used fractions will be random numbers distributed with a gauss with mean
2268 // being the corresponding particle fraction and sigma it's error.
2269 // Note that in this case only the fraction of a random species is varied in this way. The other fractions
2270 // will be re-normalised according their statistical errors.
2271 // The same holds for the systematic error of species "takeIntoAccountSpeciesSysError", but the random number will be
2272 // uniformly distributed within [mean - sys, mean + sys] and the re-normalisation will be weighted with the systematic errors.
2273 // Note that the fractions will be calculated first with only the systematic error taken into account (if desired), including
2274 // re-normalisation. Then, the resulting fractions will be used to calculate the final fractions - either with statistical error
2275 // or without. The species, for which the error will be used for smearing, is the same for sys and stat error.
2277 Double_t prob[AliPID::kSPECIES];
2278 Int_t randomSpecies = (smearByError || takeIntoAccountSysError) ? (Int_t)(fRandom->Rndm() * AliPID::kSPECIES) : -1;
2279 Bool_t success = GetParticleFractions(trackPt, jetPt, centralityPercentile, prob, randomSpecies, randomSpecies);
2282 return AliPID::kUnknown;
2284 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2286 if (rnd <= prob[AliPID::kPion])
2287 return AliPID::kPion;
2288 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon])
2289 return AliPID::kKaon;
2290 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton])
2291 return AliPID::kProton;
2292 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton] + prob[AliPID::kElectron])
2293 return AliPID::kElectron;
2295 return AliPID::kMuon; //else it must be a muon (only species left)
2299 //_____________________________________________________________________________
2300 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::GenerateDetectorResponse(AliAnalysisTaskPID::ErrorCode errCode,
2301 Double_t mean, Double_t sigma,
2302 Double_t* responses, Int_t nResponses,
2305 // Generate detector response. If a previous generation was not successful or there is something wrong with this signal generation,
2306 // the function will return kFALSE
2310 // Reset response array
2311 for (Int_t i = 0; i < nResponses; i++)
2312 responses[i] = -999;
2314 if (errCode == kError)
2317 ErrorCode ownErrCode = kNoErrors;
2319 if (fUseConvolutedGaus && !usePureGaus) {
2320 // In case of convoluted gauss, calculate the probability density only once to save a lot of time!
2322 TH1* hProbDensity = 0x0;
2323 ownErrCode = SetParamsForConvolutedGaus(mean, sigma);
2324 if (ownErrCode == kError)
2327 hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
2329 for (Int_t i = 0; i < nResponses; i++) {
2330 responses[i] = hProbDensity->GetRandom();
2331 //responses[i] fConvolutedGausDeltaPrime->GetRandom(); // MUCH slower than using the binned version via the histogram
2335 for (Int_t i = 0; i < nResponses; i++) {
2336 responses[i] = fRandom->Gaus(mean, sigma);
2340 // If forwarded error code was a warning (error case has been handled before), return a warning
2341 if (errCode == kWarning)
2344 return ownErrCode; // Forward success/warning
2348 //_____________________________________________________________________________
2349 void AliAnalysisTaskPID::PrintSettings(Bool_t printSystematicsSettings) const
2351 // Print current settings.
2353 printf("\n\nSettings for task %s:\n", GetName());
2354 printf("Is pPb/Pbp: %d -> %s\n", GetIsPbpOrpPb(), GetIsPbpOrpPb() ? "Adapting vertex cuts" : "Using standard vertex cuts");
2355 printf("Track cuts: %s\n", fTrackFilter ? fTrackFilter->GetTitle() : "-");
2356 printf("Eta cut: %.2f <= |eta| <= %.2f\n", GetEtaAbsCutLow(), GetEtaAbsCutUp());
2357 printf("Phi' cut: %d\n", GetUsePhiCut());
2358 printf("TPCCutMIGeo: %d\n", GetUseTPCCutMIGeo());
2359 if (GetUseTPCCutMIGeo()) {
2360 printf("GetCutGeo: %f\n", GetCutGeo());
2361 printf("GetCutNcr: %f\n", GetCutNcr());
2362 printf("GetCutNcl: %f\n", GetCutNcl());
2364 printf("TPCnclCut: %d\n", GetUseTPCnclCut());
2365 if (GetUseTPCnclCut()) {
2366 printf("GetCutPureNcl: %d\n", GetCutPureNcl());
2371 printf("Centrality estimator: %s\n", GetCentralityEstimator().Data());
2375 printf("Pile up rejection type: %d\n", (Int_t)fPileUpRejectionType);
2379 printf("Use MC-ID for signal generation: %d\n", GetUseMCidForGeneration());
2380 printf("Use ITS: %d\n", GetUseITS());
2381 printf("Use TOF: %d\n", GetUseTOF());
2382 printf("Use priors: %d\n", GetUsePriors());
2383 printf("Use TPC default priors: %d\n", GetUseTPCDefaultPriors());
2384 printf("Use convoluted Gauss: %d\n", GetUseConvolutedGaus());
2385 printf("Accuracy of non-Gaussian tail: %e\n", GetAccuracyNonGaussianTail());
2386 printf("Take into account muons: %d\n", GetTakeIntoAccountMuons());
2387 printf("TOF mode: %d\n", GetTOFmode());
2388 printf("\nParams for transition from gauss to asymmetric shape:\n");
2389 printf("[0]: %e\n", GetConvolutedGaussTransitionPar(0));
2390 printf("[1]: %e\n", GetConvolutedGaussTransitionPar(1));
2391 printf("[2]: %e\n", GetConvolutedGaussTransitionPar(2));
2395 printf("Do PID: %d\n", fDoPID);
2396 printf("Do Efficiency: %d\n", fDoEfficiency);
2397 printf("Do PtResolution: %d\n", fDoPtResolution);
2398 printf("Do dEdxCheck: %d\n", fDoDeDxCheck);
2399 printf("Do binZeroStudy: %d\n", fDoBinZeroStudy);
2403 printf("Input from other task: %d\n", GetInputFromOtherTask());
2404 printf("Store additional jet information: %d\n", GetStoreAdditionalJetInformation());
2405 printf("Store centrality percentile: %d", GetStoreCentralityPercentile());
2407 if (printSystematicsSettings)
2408 PrintSystematicsSettings();
2414 //_____________________________________________________________________________
2415 void AliAnalysisTaskPID::PrintSystematicsSettings() const
2417 // Print current settings for systematic studies.
2419 printf("\n\nSettings for systematics for task %s:\n", GetName());
2420 printf("SplinesThr:\t%f\n", GetSystematicScalingSplinesThreshold());
2421 printf("SplinesBelowThr:\t%f\n", GetSystematicScalingSplinesBelowThreshold());
2422 printf("SplinesAboveThr:\t%f\n", GetSystematicScalingSplinesAboveThreshold());
2423 printf("EtaCorrMomThr:\t%f\n", GetSystematicScalingEtaCorrectionMomentumThr());
2424 printf("EtaCorrLowP:\t%f\n", GetSystematicScalingEtaCorrectionLowMomenta());
2425 printf("EtaCorrHighP:\t%f\n", GetSystematicScalingEtaCorrectionHighMomenta());
2426 printf("SigmaParaThr:\t%f\n", GetSystematicScalingEtaSigmaParaThreshold());
2427 printf("SigmaParaBelowThr:\t%f\n", GetSystematicScalingEtaSigmaParaBelowThreshold());
2428 printf("SigmaParaAboveThr:\t%f\n", GetSystematicScalingEtaSigmaParaAboveThreshold());
2429 printf("MultCorr:\t%f\n", GetSystematicScalingMultCorrection());
2430 printf("TOF mode: %d\n", GetTOFmode());
2436 //_____________________________________________________________________________
2437 Bool_t AliAnalysisTaskPID::ProcessTrack(const AliVTrack* track, Int_t particlePDGcode, Double_t centralityPercentile,
2440 // Process the track (generate expected response, fill histos, etc.).
2441 // particlePDGcode == 0 means data. Otherwise, the corresponding MC ID will be assumed.
2443 //Printf("Debug: Task %s is starting to process track: dEdx %f, pTPC %f, eta %f, ncl %d\n", GetName(), track->GetTPCsignal(), track->GetTPCmomentum(),
2444 // track->Eta(), track->GetTPCsignalN());
2447 printf("File: %s, Line: %d: ProcessTrack\n", (char*)__FILE__, __LINE__);
2449 if (!fDoPID && !fDoDeDxCheck && !fDoPtResolution)
2453 printf("File: %s, Line: %d: ProcessTrack -> Processing started\n", (char*)__FILE__, __LINE__);
2455 const Bool_t isMC = (particlePDGcode == 0) ? kFALSE : kTRUE;
2460 if (TMath::Abs(particlePDGcode) == 211) {//Pion
2463 else if (TMath::Abs(particlePDGcode) == 321) {//Kaon
2466 else if (TMath::Abs(particlePDGcode) == 2212) {//Proton
2469 else if (TMath::Abs(particlePDGcode) == 11) {//Electron
2472 else if (TMath::Abs(particlePDGcode) == 13) {//Muon
2475 else // In MC-ID case, set to underflow bin such that the response from this track is only used for unidentified signal generation
2476 // or signal generation with PID response and the track is still there (as in data) - e.g. relevant w.r.t. deuterons.
2477 // This is important to be as much as possible consistent with data. And the tracks can still be removed by disabling the
2478 // underflow bin for the projections
2483 //Double_t p = track->GetP();
2484 const Double_t pTPC = track->GetTPCmomentum();
2485 Double_t pT = track->Pt();
2487 Double_t z = -1, xi = -1;
2488 GetJetTrackObservables(pT, jetPt, z, xi);
2491 Double_t trackCharge = track->Charge();
2494 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
2495 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
2496 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
2500 Printf("Skipping track with strange dEdx value: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), pTPC,
2501 track->Eta(), track->GetTPCsignalN());
2505 // Completely remove tracks from light nuclei defined by el and pr <dEdx> as function of pT.
2506 // A very loose cut to be sure not to throw away electrons and/or protons
2507 Double_t nSigmaPr = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kProton);
2508 Double_t nSigmaEl = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kElectron);
2510 if ((pTPC >= 0.3 && (nSigmaPr > 10 && nSigmaEl > 10)) ||
2511 (pTPC < 0.3 && (nSigmaPr > 15 && nSigmaEl > 15))) {
2513 Printf("Skipping track which seems to be a light nucleus: dEdx %f, pTPC %f, pT %f, eta %f, ncl %d, nSigmaPr %f, nSigmaEl %f\n",
2514 track->GetTPCsignal(), pTPC, pT, track->Eta(), track->GetTPCsignalN(), nSigmaPr, nSigmaEl);
2519 Double_t dEdxEl, dEdxKa, dEdxPi, dEdxMu, dEdxPr;
2520 Double_t sigmaEl, sigmaKa, sigmaPi, sigmaMu, sigmaPr;
2522 if (fDoAnySystematicStudiesOnTheExpectedSignal) {
2523 // Get the uncorrected signal first and the corresponding correction factors.
2524 // Then modify the correction factors and properly recalculate the corrected dEdx
2526 // Get pure spline values for dEdx_expected, without any correction
2527 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2528 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2529 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2530 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2531 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2532 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2534 // Scale splines, if desired
2535 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
2536 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
2538 // Tune turn-on of correction for pions (not so relevant for the other species, since at very large momenta)
2540 Double_t scaleFactor = 1.;
2541 Double_t usedSystematicScalingSplines = 1.;
2543 bg = pTPC / AliPID::ParticleMass(AliPID::kElectron);
2544 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2545 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2546 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2547 dEdxEl *= usedSystematicScalingSplines;
2549 bg = pTPC / AliPID::ParticleMass(AliPID::kKaon);
2550 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2551 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2552 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2553 dEdxKa *= usedSystematicScalingSplines;
2555 bg = pTPC / AliPID::ParticleMass(AliPID::kPion);
2556 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2557 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2558 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2559 dEdxPi *= usedSystematicScalingSplines;
2561 if (fTakeIntoAccountMuons) {
2562 bg = pTPC / AliPID::ParticleMass(AliPID::kMuon);
2563 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2564 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2565 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2566 dEdxMu *= usedSystematicScalingSplines;
2570 bg = pTPC / AliPID::ParticleMass(AliPID::kProton);
2571 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2572 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2573 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2574 dEdxPr *= usedSystematicScalingSplines;
2577 // Get the eta correction factors for the (modified) expected dEdx
2578 Double_t etaCorrEl = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxEl) : 1.;
2579 Double_t etaCorrKa = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxKa) : 1.;
2580 Double_t etaCorrPi = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPi) : 1.;
2581 Double_t etaCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCEtaCorrection() ?
2582 fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxMu) : 1.;
2583 Double_t etaCorrPr = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPr) : 1.;
2585 // Scale eta correction factors, if desired (and eta correction maps are to be used, otherwise it is not possible!)
2586 if (fPIDResponse->UseTPCEtaCorrection() &&
2587 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon ||
2588 TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon)) {
2589 // Since we do not want to scale the splines with this, but only the eta variation, only scale the deviation of the correction factor!
2590 // E.g. if we would have a flat eta depence fixed at 1.0, we would shift the whole thing equal to shifting the splines by the same factor!
2593 // Due to additional azimuthal effects, there is an additional eta dependence for low momenta which is not corrected successfully so far.
2594 // One can assign a different (higher) systematic scale factor for this low-p region and a threshold which separates low- and high-p.
2595 // An ERF will be used to get (as a function of p_TPC) from one correction factor to the other within roughly 0.2 GeV/c
2596 Double_t usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionHighMomenta;
2598 if (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - fSystematicScalingEtaCorrectionLowMomenta) > fgkEpsilon) {
2599 const Double_t fractionHighMomentumScaleFactor = 0.5 * (1. + TMath::Erf((pTPC - fSystematicScalingEtaCorrectionMomentumThr) / 0.1));
2600 usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionLowMomenta * (1 - fractionHighMomentumScaleFactor)
2601 + fSystematicScalingEtaCorrectionHighMomenta * fractionHighMomentumScaleFactor;
2604 Double_t maxEtaVariationEl = GetMaxEtaVariation(dEdxEl);
2605 etaCorrEl = etaCorrEl * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrEl - 1.0) / maxEtaVariationEl);
2607 Double_t maxEtaVariationKa = GetMaxEtaVariation(dEdxKa);
2608 etaCorrKa = etaCorrKa * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrKa - 1.0) / maxEtaVariationKa);
2610 Double_t maxEtaVariationPi = GetMaxEtaVariation(dEdxPi);
2611 etaCorrPi = etaCorrPi * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPi - 1.0) / maxEtaVariationPi);
2613 if (fTakeIntoAccountMuons) {
2614 Double_t maxEtaVariationMu = GetMaxEtaVariation(dEdxMu);
2615 etaCorrMu = etaCorrMu * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrMu - 1.0) / maxEtaVariationMu);
2620 Double_t maxEtaVariationPr = GetMaxEtaVariation(dEdxPr);
2621 etaCorrPr = etaCorrPr * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPr - 1.0) / maxEtaVariationPr);
2625 etaCorrEl = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrEl - 1.0);
2626 etaCorrKa = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrKa - 1.0);
2627 etaCorrPi = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPi - 1.0);
2628 etaCorrMu = fTakeIntoAccountMuons ? (1.0 + usedSystematicScalingEtaCorrection * (etaCorrMu - 1.0)) : 1.0;
2629 etaCorrPr = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPr - 1.0);
2633 // Get the multiplicity correction factors for the (modified) expected dEdx
2634 const Int_t currEvtMultiplicity = fPIDResponse->GetTPCResponse().GetCurrentEventMultiplicity();
2636 Double_t multiplicityCorrEl = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2637 dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2638 Double_t multiplicityCorrKa = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2639 dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2640 Double_t multiplicityCorrPi = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2641 dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2642 Double_t multiplicityCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2643 fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track, dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2644 Double_t multiplicityCorrPr = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2645 dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2647 Double_t multiplicityCorrSigmaEl = fPIDResponse->UseTPCMultiplicityCorrection() ?
2648 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2649 Double_t multiplicityCorrSigmaKa = fPIDResponse->UseTPCMultiplicityCorrection() ?
2650 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2651 Double_t multiplicityCorrSigmaPi = fPIDResponse->UseTPCMultiplicityCorrection() ?
2652 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2653 Double_t multiplicityCorrSigmaMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2654 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2655 Double_t multiplicityCorrSigmaPr = fPIDResponse->UseTPCMultiplicityCorrection() ?
2656 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2658 // Scale multiplicity correction factors, if desired (and multiplicity correction functions are to be used, otherwise it is not possible!)
2659 if (fPIDResponse->UseTPCMultiplicityCorrection() && TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
2660 // Since we do not want to scale the splines with this, but only the multiplicity variation, only scale the deviation of the correction factor!
2661 // E.g. if we would have a flat mult depence fix at 1.0, we would shift the whole thing equal to shifting the splines by the same factor!
2663 multiplicityCorrEl = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrEl - 1.0);
2664 multiplicityCorrKa = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrKa - 1.0);
2665 multiplicityCorrPi = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPi - 1.0);
2666 multiplicityCorrMu = fTakeIntoAccountMuons ? (1.0 + fSystematicScalingMultCorrection * (multiplicityCorrMu - 1.0)) : 1.0;
2667 multiplicityCorrPr = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPr - 1.0);
2670 // eta correction must be enabled in order to use the new sigma parametrisation maps. Since this is the absolute sigma
2671 // for a track calculated with the unscaled paramaters, we have to devide out dEdxExpectedEtaCorrected and then need
2672 // to scale with the multiplicitySigmaCorrFactor * fSystematicScalingEtaSigmaPara. In the end, one has to scale with the
2673 // (modified) dEdx to get the absolute sigma
2674 // This means there is no extra parameter for the multiplicitySigmaCorrFactor, but only for the sigma map itself.
2675 // This is valid, since it appears only as a product. One has to assume a larger systematic shift in case of additional
2676 // multiplicity dependence....
2678 Bool_t doSigmaSystematics = (TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
2679 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon);
2682 Double_t dEdxElExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2684 Double_t systematicScalingEtaSigmaParaEl = 1.;
2685 if (doSigmaSystematics) {
2686 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxElExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2687 systematicScalingEtaSigmaParaEl = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2688 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2690 Double_t sigmaRelEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2692 / dEdxElExpected * systematicScalingEtaSigmaParaEl * multiplicityCorrSigmaEl;
2695 Double_t dEdxKaExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2697 Double_t systematicScalingEtaSigmaParaKa = 1.;
2698 if (doSigmaSystematics) {
2699 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxKaExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2700 systematicScalingEtaSigmaParaKa = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2701 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2703 Double_t sigmaRelKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2705 / dEdxKaExpected * systematicScalingEtaSigmaParaKa * multiplicityCorrSigmaKa;
2708 Double_t dEdxPiExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2710 Double_t systematicScalingEtaSigmaParaPi = 1.;
2711 if (doSigmaSystematics) {
2712 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPiExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2713 systematicScalingEtaSigmaParaPi = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2714 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2716 Double_t sigmaRelPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2718 / dEdxPiExpected * systematicScalingEtaSigmaParaPi * multiplicityCorrSigmaPi;
2721 Double_t sigmaRelMu = 999.;
2722 if (fTakeIntoAccountMuons) {
2723 Double_t dEdxMuExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2725 Double_t systematicScalingEtaSigmaParaMu = 1.;
2726 if (doSigmaSystematics) {
2727 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxMuExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2728 systematicScalingEtaSigmaParaMu = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2729 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2731 sigmaRelMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kTRUE, kFALSE)
2732 / dEdxMuExpected * systematicScalingEtaSigmaParaMu * multiplicityCorrSigmaMu;
2736 Double_t dEdxPrExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2738 Double_t systematicScalingEtaSigmaParaPr = 1.;
2739 if (doSigmaSystematics) {
2740 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPrExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2741 systematicScalingEtaSigmaParaPr = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2742 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2744 Double_t sigmaRelPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2746 / dEdxPrExpected * systematicScalingEtaSigmaParaPr * multiplicityCorrSigmaPr;
2748 // Now scale the (possibly modified) spline values with the (possibly modified) correction factors
2749 dEdxEl *= etaCorrEl * multiplicityCorrEl;
2750 dEdxKa *= etaCorrKa * multiplicityCorrKa;
2751 dEdxPi *= etaCorrPi * multiplicityCorrPi;
2752 dEdxMu *= etaCorrMu * multiplicityCorrMu;
2753 dEdxPr *= etaCorrPr * multiplicityCorrPr;
2755 // Finally, get the absolute sigma
2756 sigmaEl = sigmaRelEl * dEdxEl;
2757 sigmaKa = sigmaRelKa * dEdxKa;
2758 sigmaPi = sigmaRelPi * dEdxPi;
2759 sigmaMu = sigmaRelMu * dEdxMu;
2760 sigmaPr = sigmaRelPr * dEdxPr;
2764 // No systematic studies on expected signal - just take it as it comes from the TPCPIDResponse
2765 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2766 fPIDResponse->UseTPCEtaCorrection(),
2767 fPIDResponse->UseTPCMultiplicityCorrection());
2768 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2769 fPIDResponse->UseTPCEtaCorrection(),
2770 fPIDResponse->UseTPCMultiplicityCorrection());
2771 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2772 fPIDResponse->UseTPCEtaCorrection(),
2773 fPIDResponse->UseTPCMultiplicityCorrection());
2774 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2775 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2776 fPIDResponse->UseTPCEtaCorrection(),
2777 fPIDResponse->UseTPCMultiplicityCorrection());
2778 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2779 fPIDResponse->UseTPCEtaCorrection(),
2780 fPIDResponse->UseTPCMultiplicityCorrection());
2782 sigmaEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2783 fPIDResponse->UseTPCEtaCorrection(),
2784 fPIDResponse->UseTPCMultiplicityCorrection());
2785 sigmaKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2786 fPIDResponse->UseTPCEtaCorrection(),
2787 fPIDResponse->UseTPCMultiplicityCorrection());
2788 sigmaPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2789 fPIDResponse->UseTPCEtaCorrection(),
2790 fPIDResponse->UseTPCMultiplicityCorrection());
2791 sigmaMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2792 fPIDResponse->UseTPCEtaCorrection(),
2793 fPIDResponse->UseTPCMultiplicityCorrection());
2794 sigmaPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2795 fPIDResponse->UseTPCEtaCorrection(),
2796 fPIDResponse->UseTPCMultiplicityCorrection());
2799 Double_t deltaPrimeElectron = (dEdxEl > 0) ? dEdxTPC / dEdxEl : -1;
2801 Printf("Error: Expected TPC signal <= 0 for electron hypothesis");
2805 Double_t deltaPrimeKaon = (dEdxKa > 0) ? dEdxTPC / dEdxKa : -1;
2807 Printf("Error: Expected TPC signal <= 0 for kaon hypothesis");
2811 Double_t deltaPrimePion = (dEdxPi > 0) ? dEdxTPC / dEdxPi : -1;
2813 Printf("Error: Expected TPC signal <= 0 for pion hypothesis");
2817 Double_t deltaPrimeProton = (dEdxPr > 0) ? dEdxTPC / dEdxPr : -1;
2819 Printf("Error: Expected TPC signal <= 0 for proton hypothesis");
2824 printf("File: %s, Line: %d: ProcessTrack -> Compute probabilities\n", (char*)__FILE__, __LINE__);
2827 // Use probabilities to weigh the response generation for the different species.
2828 // Also determine the most probable particle type.
2829 Double_t prob[AliPID::kSPECIESC];
2830 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2833 fPIDcombined->ComputeProbabilities(track, fPIDResponse, prob);
2835 // If muons are not to be taken into account, just set their probability to zero and normalise the remaining probabilities later
2836 if (!fTakeIntoAccountMuons)
2837 prob[AliPID::kMuon] = 0;
2839 // Priors might cause problems in case of mismatches, i.e. mismatch particles will be identified as pions.
2840 // Can be easily caught for low p_TPC by just setting pion (and muon) probs to zero, if dEdx is larger than
2841 // expected dEdx of electrons and kaons
2842 if (pTPC < 1. && dEdxTPC > dEdxEl && dEdxTPC > dEdxKa) {
2843 prob[AliPID::kMuon] = 0;
2844 prob[AliPID::kPion] = 0;
2848 // Bug: One can set the number of species for PIDcombined, but PIDcombined will call PIDresponse, which writes without testing
2849 // the probs for kSPECIESC (including light nuclei) into the array.
2850 // In this case, when only kSPECIES are considered, the probabilities have to be rescaled!
2853 // 1. If the most probable PID is a light nucleus and above expected dEdx + 5 sigma of el to be sure not to mix up things in the
2854 // high-pT region (also contribution there completely negligable!)
2855 // 2. If dEdx is larger than the expected dEdx + 5 sigma of el and pr, it is most likely a light nucleus
2856 // (if dEdx is more than 5 sigma away from expectation, flat TPC probs are set... and the light nuclei splines are not
2859 // The highest expected dEdx is either for pr or for el. Assign 100% probability to the species with highest expected dEdx then.
2860 // In all other cases: Throw away light nuclei probs and rescale other probs to 100%.
2862 // Find most probable species for the ID
2863 Int_t maxIndex = TMath::LocMax(AliPID::kSPECIESC, prob);
2865 if ((prob[maxIndex] > 0 && maxIndex >= AliPID::kSPECIES && dEdxTPC > dEdxEl + 5. * sigmaEl) ||
2866 (dEdxTPC > dEdxEl + 5. * sigmaEl && dEdxTPC > dEdxPr + 5. * sigmaPr)) {
2867 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2870 if (dEdxEl > dEdxPr) {
2871 prob[AliPID::kElectron] = 1.;
2872 maxIndex = AliPID::kElectron;
2875 prob[AliPID::kProton] = 1.;
2876 maxIndex = AliPID::kProton;
2880 for (Int_t i = AliPID::kSPECIES; i < AliPID::kSPECIESC; i++)
2883 Double_t probSum = 0.;
2884 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2888 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2892 // If all probabilities are equal (should only happen if no priors are used), set most probable PID to pion
2893 // because LocMax returns just the first maximal value (i.e. AliPID::kElectron)
2894 if (TMath::Abs(prob[maxIndex] - 1. / AliPID::kSPECIES) < 1e-5)
2895 maxIndex = AliPID::kPion;
2897 // In all other cases, the maximum remains untouched from the scaling (and is < AliPID::kSPECIES by construction)
2901 // Generate the expected responses in DeltaPrime and translate to real dEdx. Only take responses for exactly that species
2902 // (i.e. with pre-PID)
2904 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
2906 ErrorCode errCode = kNoErrors;
2909 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check\n", (char*)__FILE__, __LINE__);
2912 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
2915 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
2918 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
2921 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
2923 if (errCode == kNoErrors) {
2924 Double_t genEntry[kDeDxCheckNumAxes];
2925 genEntry[kDeDxCheckJetPt] = jetPt;
2926 genEntry[kDeDxCheckEtaAbs] = TMath::Abs(track->Eta());
2927 genEntry[kDeDxCheckP] = pTPC;
2930 for (Int_t n = 0; n < numGenEntries; n++) {
2931 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
2932 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2934 // Consider generated response as originating from...
2935 if (rnd <= prob[AliPID::kElectron]) {
2936 genEntry[kDeDxCheckPID] = 0; // ... an electron
2937 genEntry[kDeDxCheckDeDx] = fGenRespElDeltaPrimeEl[n] * dEdxEl;
2939 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon]) {
2940 genEntry[kDeDxCheckPID] = 1; // ... a kaon
2941 genEntry[kDeDxCheckDeDx] = fGenRespKaDeltaPrimeKa[n] * dEdxKa;
2943 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion]) {
2944 genEntry[kDeDxCheckPID] = 2; // ... a pion (or a muon)
2945 genEntry[kDeDxCheckDeDx] = fGenRespPiDeltaPrimePi[n] * dEdxPi;
2948 genEntry[kDeDxCheckPID] = 3; // ... a proton
2949 genEntry[kDeDxCheckDeDx] = fGenRespPrDeltaPrimePr[n] * dEdxPr;
2952 fDeDxCheck->Fill(genEntry);
2957 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check done\n", (char*)__FILE__, __LINE__);
2960 if (fDoPtResolution) {
2961 // Check shared clusters, which is done together with the pT resolution
2962 Double_t qaEntry[kQASharedClsNumAxes];
2963 qaEntry[kQASharedClsJetPt] = jetPt;
2964 qaEntry[kQASharedClsPt] = pT;
2965 qaEntry[kDeDxCheckP] = pTPC;
2966 qaEntry[kQASharedClsNumSharedCls] = track->GetTPCSharedMapPtr()->CountBits();
2969 // iRowInd == -1 for "all rows w/o multiple counting"
2970 qaEntry[kQASharedClsPadRow] = iRowInd;
2971 fQASharedCls->Fill(qaEntry);
2973 // Fill hist for every pad row with shared cluster
2974 for (iRowInd = 0; iRowInd < 159; iRowInd++) {
2975 if (track->GetTPCSharedMapPtr()->TestBitNumber(iRowInd)) {
2976 qaEntry[kQASharedClsPadRow] = iRowInd;
2977 fQASharedCls->Fill(qaEntry);
2986 // Clean up the most probable PID for low momenta (not an issue for the probabilities, since fractions small,
2987 // but to get clean (and nice looking) templates (if most probable PID is used instead of generated responses), it should be done).
2988 // Problem: If more than 5 sigma away (and since priors also included), most probable PID for dEdx around protons could be pions.
2989 // Idea: Only clean selection for K and p possible. So, just take for the most probable PID the probs from TPC only calculated
2990 // by hand without restriction to 5 sigma and without priors. This will not affect the template generation, but afterwards one
2991 // can replace the K and p templates with the most probable PID distributions, so all other species templates remain the same.
2992 // I.e. it doesn't hurt if the most probable PID is distributed incorrectly between el, pi, mu.
2993 Bool_t maxIndexSetManually = kFALSE;
2996 Double_t probManualTPC[AliPID::kSPECIES];
2997 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2998 probManualTPC[i] = 0;
3000 probManualTPC[AliPID::kElectron] = TMath::Exp(-0.5*(dEdxTPC-dEdxEl)*(dEdxTPC-dEdxEl)/(sigmaEl*sigmaEl))/sigmaEl;
3001 // Muons are not important here, just ignore and save processing time
3002 probManualTPC[AliPID::kMuon] = 0.;//TMath::Exp(-0.5*(dEdxTPC-dEdxMu)*(dEdxTPC-dEdxMu)/(sigmaMu*sigmaMu))/sigmaMu;
3003 probManualTPC[AliPID::kPion] = TMath::Exp(-0.5*(dEdxTPC-dEdxPi)*(dEdxTPC-dEdxPi)/(sigmaPi*sigmaPi))/sigmaPi;
3004 probManualTPC[AliPID::kKaon] = TMath::Exp(-0.5*(dEdxTPC-dEdxKa)*(dEdxTPC-dEdxKa)/(sigmaKa*sigmaKa))/sigmaKa;
3005 probManualTPC[AliPID::kProton] = TMath::Exp(-0.5*(dEdxTPC-dEdxPr)*(dEdxTPC-dEdxPr)/(sigmaPr*sigmaPr))/sigmaPr;
3007 const Int_t maxIndexManualTPC = TMath::LocMax(AliPID::kSPECIES, probManualTPC);
3008 // Should always be > 0, but in case the dEdx is far off such that the machine accuracy sets every prob to zero,
3009 // better take the "old" result
3010 if (probManualTPC[maxIndexManualTPC] > 0.)
3011 maxIndex = maxIndexManualTPC;
3013 maxIndexSetManually = kTRUE;
3017 // Translate from AliPID numbering to numbering of this class
3018 if (prob[maxIndex] > 0 || maxIndexSetManually) {
3019 if (maxIndex == AliPID::kElectron)
3021 else if (maxIndex == AliPID::kKaon)
3023 else if (maxIndex == AliPID::kMuon)
3025 else if (maxIndex == AliPID::kPion)
3027 else if (maxIndex == AliPID::kProton)
3033 // Only take track into account for expectation values, if valid pid response is available.. Otherwise: Set to underflow bin.
3039 //For testing: Swap p<->pT to analyse pure p-dependence => Needs to be removed later
3045 TOFpidInfo tofPIDinfo = GetTOFType(track, fTOFmode);
3047 Double_t entry[fStoreAdditionalJetInformation ? kDataNumAxes : kDataNumAxes - fgkNumJetAxes];
3048 entry[kDataMCID] = binMC;
3049 entry[kDataSelectSpecies] = 0;
3050 entry[kDataPt] = pT;
3051 entry[kDataDeltaPrimeSpecies] = deltaPrimeElectron;
3052 entry[kDataCentrality] = centralityPercentile;
3054 if (fStoreAdditionalJetInformation) {
3055 entry[kDataJetPt] = jetPt;
3057 entry[kDataXi] = xi;
3060 entry[GetIndexOfChargeAxisData()] = trackCharge;
3061 entry[GetIndexOfTOFpidInfoAxisData()] = tofPIDinfo;
3063 fhPIDdataAll->Fill(entry);
3065 entry[kDataSelectSpecies] = 1;
3066 entry[kDataDeltaPrimeSpecies] = deltaPrimeKaon;
3067 fhPIDdataAll->Fill(entry);
3069 entry[kDataSelectSpecies] = 2;
3070 entry[kDataDeltaPrimeSpecies] = deltaPrimePion;
3071 fhPIDdataAll->Fill(entry);
3073 entry[kDataSelectSpecies] = 3;
3074 entry[kDataDeltaPrimeSpecies] = deltaPrimeProton;
3075 fhPIDdataAll->Fill(entry);
3078 // Construct the expected shape for the transition p -> pT
3080 Double_t genEntry[fStoreAdditionalJetInformation ? kGenNumAxes : kGenNumAxes - fgkNumJetAxes];
3081 genEntry[kGenMCID] = binMC;
3082 genEntry[kGenSelectSpecies] = 0;
3083 genEntry[kGenPt] = pT;
3084 genEntry[kGenDeltaPrimeSpecies] = -999;
3085 genEntry[kGenCentrality] = centralityPercentile;
3087 if (fStoreAdditionalJetInformation) {
3088 genEntry[kGenJetPt] = jetPt;
3089 genEntry[kGenZ] = z;
3090 genEntry[kGenXi] = xi;
3093 genEntry[GetIndexOfChargeAxisGen()] = trackCharge;
3094 genEntry[GetIndexOfTOFpidInfoAxisGen()] = tofPIDinfo;
3096 // Generate numGenEntries "responses" with fluctuations around the expected values.
3097 // fgkMaxNumGenEntries = 500 turned out to give reasonable templates even for highest track pT in 15-20 GeV/c jet pT bin.
3098 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
3100 /*OLD: Different number of responses depending on pT and jet pT for fgkMaxNumGenEntries = 1000
3101 * => Problem: If threshold to higher number of responses inside a bin (or after rebinning), then the template
3102 * is biased to the higher pT.
3103 // Generate numGenEntries "responses" with fluctuations around the expected values.
3104 // The higher the (transverse) momentum, the more "responses" will be generated in order not to run out of statistics too fast.
3105 Int_t numGenEntries = 10;
3107 // Jets have even worse statistics, therefore, scale numGenEntries further
3109 numGenEntries *= 20;
3110 else if (jetPt >= 20)
3111 numGenEntries *= 10;
3112 else if (jetPt >= 10)
3117 // Do not generate more entries than available in memory!
3118 if (numGenEntries > fgkMaxNumGenEntries)// fgkMaxNumGenEntries = 1000
3119 numGenEntries = fgkMaxNumGenEntries;
3123 ErrorCode errCode = kNoErrors;
3126 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses\n", (char*)__FILE__, __LINE__);
3129 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
3130 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxKa, sigmaEl / dEdxKa, fGenRespElDeltaPrimeKa, numGenEntries);
3131 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPi, sigmaEl / dEdxPi, fGenRespElDeltaPrimePi, numGenEntries);
3132 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPr, sigmaEl / dEdxPr, fGenRespElDeltaPrimePr, numGenEntries);
3135 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxEl, sigmaKa / dEdxEl, fGenRespKaDeltaPrimeEl, numGenEntries);
3136 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
3137 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPi, sigmaKa / dEdxPi, fGenRespKaDeltaPrimePi, numGenEntries);
3138 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPr, sigmaKa / dEdxPr, fGenRespKaDeltaPrimePr, numGenEntries);
3141 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxEl, sigmaPi / dEdxEl, fGenRespPiDeltaPrimeEl, numGenEntries);
3142 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxKa, sigmaPi / dEdxKa, fGenRespPiDeltaPrimeKa, numGenEntries);
3143 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
3144 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxPr, sigmaPi / dEdxPr, fGenRespPiDeltaPrimePr, numGenEntries);
3146 // Muons, if desired
3147 if (fTakeIntoAccountMuons) {
3148 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxEl, sigmaMu / dEdxEl, fGenRespMuDeltaPrimeEl, numGenEntries);
3149 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxKa, sigmaMu / dEdxKa, fGenRespMuDeltaPrimeKa, numGenEntries);
3150 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPi, sigmaMu / dEdxPi, fGenRespMuDeltaPrimePi, numGenEntries);
3151 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPr, sigmaMu / dEdxPr, fGenRespMuDeltaPrimePr, numGenEntries);
3155 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxEl, sigmaPr / dEdxEl, fGenRespPrDeltaPrimeEl, numGenEntries);
3156 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxKa, sigmaPr / dEdxKa, fGenRespPrDeltaPrimeKa, numGenEntries);
3157 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxPi, sigmaPr / dEdxPi, fGenRespPrDeltaPrimePi, numGenEntries);
3158 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
3160 if (errCode != kNoErrors) {
3161 if (errCode == kWarning && fDebug > 1) {
3162 Printf("Warning: Questionable detector response for track, most likely due to very low number of PID clusters! Debug output (dEdx_expected, sigma_expected):");
3165 Printf("Error: Failed to generate detector response for track - skipped! Debug output (dEdx_expected, sigma_expected):");
3168 Printf("Pr: %e, %e", dEdxPr, sigmaPr);
3169 Printf("Pi: %e, %e", dEdxPi, sigmaPi);
3170 Printf("El: %e, %e", dEdxEl, sigmaEl);
3171 Printf("Mu: %e, %e", dEdxMu, sigmaMu);
3172 Printf("Ka: %e, %e", dEdxKa, sigmaKa);
3173 Printf("track: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), track->GetTPCmomentum(), track->Eta(),
3174 track->GetTPCsignalN());
3177 if (errCode != kWarning) {
3178 return kFALSE;// Skip generated response in case of error
3182 for (Int_t n = 0; n < numGenEntries; n++) {
3183 if (!isMC || !fUseMCidForGeneration) {
3184 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
3185 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
3187 // Consider generated response as originating from...
3188 if (rnd <= prob[AliPID::kElectron])
3189 genEntry[kGenMCID] = 0; // ... an electron
3190 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon])
3191 genEntry[kGenMCID] = 1; // ... a kaon
3192 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon])
3193 genEntry[kGenMCID] = 2; // ... a muon -> NOTE: prob[AliPID::kMuon] = 0 in case of fTakeIntoAccountMuons = kFALSE
3194 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion])
3195 genEntry[kGenMCID] = 3; // ... a pion
3197 genEntry[kGenMCID] = 4; // ... a proton
3201 genEntry[kGenSelectSpecies] = 0;
3202 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeEl[n];
3203 fhGenEl->Fill(genEntry);
3205 genEntry[kGenSelectSpecies] = 1;
3206 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeKa[n];
3207 fhGenEl->Fill(genEntry);
3209 genEntry[kGenSelectSpecies] = 2;
3210 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePi[n];
3211 fhGenEl->Fill(genEntry);
3213 genEntry[kGenSelectSpecies] = 3;
3214 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePr[n];
3215 fhGenEl->Fill(genEntry);
3218 genEntry[kGenSelectSpecies] = 0;
3219 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeEl[n];
3220 fhGenKa->Fill(genEntry);
3222 genEntry[kGenSelectSpecies] = 1;
3223 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeKa[n];
3224 fhGenKa->Fill(genEntry);
3226 genEntry[kGenSelectSpecies] = 2;
3227 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePi[n];
3228 fhGenKa->Fill(genEntry);
3230 genEntry[kGenSelectSpecies] = 3;
3231 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePr[n];
3232 fhGenKa->Fill(genEntry);
3235 genEntry[kGenSelectSpecies] = 0;
3236 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeEl[n];
3237 fhGenPi->Fill(genEntry);
3239 genEntry[kGenSelectSpecies] = 1;
3240 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeKa[n];
3241 fhGenPi->Fill(genEntry);
3243 genEntry[kGenSelectSpecies] = 2;
3244 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePi[n];
3245 fhGenPi->Fill(genEntry);
3247 genEntry[kGenSelectSpecies] = 3;
3248 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePr[n];
3249 fhGenPi->Fill(genEntry);
3251 if (fTakeIntoAccountMuons) {
3252 // Muons, if desired
3253 genEntry[kGenSelectSpecies] = 0;
3254 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeEl[n];
3255 fhGenMu->Fill(genEntry);
3257 genEntry[kGenSelectSpecies] = 1;
3258 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeKa[n];
3259 fhGenMu->Fill(genEntry);
3261 genEntry[kGenSelectSpecies] = 2;
3262 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePi[n];
3263 fhGenMu->Fill(genEntry);
3265 genEntry[kGenSelectSpecies] = 3;
3266 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePr[n];
3267 fhGenMu->Fill(genEntry);
3271 genEntry[kGenSelectSpecies] = 0;
3272 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeEl[n];
3273 fhGenPr->Fill(genEntry);
3275 genEntry[kGenSelectSpecies] = 1;
3276 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeKa[n];
3277 fhGenPr->Fill(genEntry);
3279 genEntry[kGenSelectSpecies] = 2;
3280 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePi[n];
3281 fhGenPr->Fill(genEntry);
3283 genEntry[kGenSelectSpecies] = 3;
3284 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePr[n];
3285 fhGenPr->Fill(genEntry);
3289 printf("File: %s, Line: %d: ProcessTrack -> Done\n", (char*)__FILE__, __LINE__);
3295 //_____________________________________________________________________________
3296 Bool_t AliAnalysisTaskPID::SetConvolutedGaussLambdaParameter(Double_t lambda)
3298 // Set the lambda parameter of the convolution to the desired value. Automatically
3299 // calculates the parameters for the transition (restricted) gauss -> convoluted gauss.
3300 fConvolutedGaussTransitionPars[2] = lambda;
3302 // Save old parameters and settings of function to restore them later:
3303 Double_t* oldFuncParams = new Double_t[fkConvolutedGausNPar];
3304 for (Int_t i = 0; i < fkConvolutedGausNPar; i++)
3305 oldFuncParams[i] = fConvolutedGausDeltaPrime->GetParameter(i);
3306 Int_t oldFuncNpx = fConvolutedGausDeltaPrime->GetNpx();
3307 Double_t oldFuncRangeLow = 0, oldFuncRangeUp = 100;
3308 fConvolutedGausDeltaPrime->GetRange(oldFuncRangeLow, oldFuncRangeUp);
3310 // Choose some sufficiently large range
3311 const Double_t rangeStart = 0.5;
3312 const Double_t rangeEnd = 2.0;
3314 // To get the parameters for the transition, just choose arbitrarily input parameters for mu and sigma
3315 // (it makes sense to choose typical values). The ratio sigma_gauss / sigma_convolution is independent
3316 // of mu and as well the difference mu_gauss - mu_convolution.
3317 Double_t muInput = 1.0;
3318 Double_t sigmaInput = fgkSigmaReferenceForTransitionPars;
3321 // Step 1: Generate distribution with input parameters
3322 const Int_t nPar = 3;
3323 Double_t inputPar[nPar] = { muInput, sigmaInput, lambda };
3325 TH1D* hInput = new TH1D("hInput", "Input distribution", 2000, rangeStart, rangeEnd);
3327 fConvolutedGausDeltaPrime->SetParameters(inputPar);
3328 fConvolutedGausDeltaPrime->SetRange(rangeStart, rangeEnd);
3329 fConvolutedGausDeltaPrime->SetNpx(2000);
3332 // The resolution and mean of the AliPIDResponse are determined in finite intervals
3333 // of ncl (also second order effects due to finite dEdx and tanTheta).
3334 // Take this into account for the transition parameters via assuming an approximately flat
3335 // distritubtion in ncl in this interval.
3336 // NOTE: The ncl interval should be the same as the one used for the sigma map creation!
3337 const Int_t nclStart = 151;
3338 const Int_t nclEnd = 160;
3339 const Int_t nclSteps = (nclEnd - nclStart) + 1;
3340 for (Int_t ncl = nclStart; ncl <= nclEnd; ncl++) {
3341 // Resolution scales with 1/sqrt(ncl)
3342 fConvolutedGausDeltaPrime->SetParameter(1, inputPar[1] * sqrt(nclEnd) / sqrt(ncl));
3343 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3345 for (Int_t i = 0; i < 50000000 / nclSteps; i++)
3346 hInput->Fill(hProbDensity->GetRandom());
3350 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3352 for (Int_t i = 0; i < 50000000; i++)
3353 hInput->Fill(hProbDensity->GetRandom());
3355 // Step 2: Fit generated distribution with restricted gaussian
3356 Int_t maxBin = hInput->GetMaximumBin();
3357 Double_t max = hInput->GetBinContent(maxBin);
3359 UChar_t usedBins = 1;
3361 max += hInput->GetBinContent(maxBin - 1);
3364 if (maxBin < hInput->GetNbinsX()) {
3365 max += hInput->GetBinContent(maxBin + 1);
3370 // NOTE: The range (<-> fraction of maximum) should be the same
3371 // as for the spline and eta maps creation
3372 const Double_t lowThreshold = hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max));
3373 const Double_t highThreshold = hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max));
3375 TFitResultPtr fitResGaussFirstStep = hInput->Fit("gaus", "QNRS", "", lowThreshold, highThreshold);
3377 TFitResultPtr fitResGauss;
3379 if ((Int_t)fitResGaussFirstStep == 0) {
3380 TF1 fGauss("fGauss", "[0]*TMath::Gaus(x, [1], [2], 1)", rangeStart, rangeEnd);
3381 fGauss.SetParameter(0, fitResGaussFirstStep->GetParams()[0]);
3382 fGauss.SetParError(0, fitResGaussFirstStep->GetErrors()[0]);
3383 fGauss.SetParameter(2, fitResGaussFirstStep->GetParams()[2]);
3384 fGauss.SetParError(2, fitResGaussFirstStep->GetErrors()[2]);
3386 fGauss.FixParameter(1, fitResGaussFirstStep->GetParams()[1]);
3387 fitResGauss = hInput->Fit(&fGauss, "QNS", "s", rangeStart, rangeEnd);
3390 fitResGauss = hInput->Fit("gaus", "QNRS", "same", rangeStart, rangeEnd);
3392 //OLD TFitResultPtr fitResGauss = hInput->Fit("gaus", "QNRS", "", hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max)),
3393 // hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max)));
3396 // Step 3: Use parameters from gaussian fit to obtain parameters for the transition "restricted gauss" -> "convoluted gauss"
3398 // 3.1 The ratio sigmaInput / sigma_gaussFit ONLY depends on lambda (which is fixed per period) -> Calculate this first
3399 // for an arbitrary (here: typical) sigma. The ratio is then ~the same for ALL sigma for given lambda!
3400 if ((Int_t)fitResGauss != 0) {
3401 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Gauss Fit failed!\n");
3402 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3403 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3404 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3407 delete [] oldFuncParams;
3412 if (fitResGauss->GetParams()[2] <= 0) {
3413 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Sigma of gauss fit <= 0!\n");
3414 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3415 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3416 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3419 delete [] oldFuncParams;
3424 // sigma correction factor
3425 fConvolutedGaussTransitionPars[1] = sigmaInput / fitResGauss->GetParams()[2];
3427 // 3.2 Now that sigma und lambda are determined, one can calculate mu by shifting the maximum to the desired position,
3428 // i.e. the maximum of the input distribution should coincide with that of the re-calculated distribution,
3429 // which is achieved by getting the same mu for the same sigma.
3430 // NOTE: For fixed lambda, the shift is proportional to sigma and independent of mu!
3431 // So, one can calculate the shift for an arbitrary fixed (here: typical)
3432 // sigma and then simply use this shift for any other sigma by scaling it correspondingly!!!
3434 // Mu shift correction:
3435 // Shift in mu (difference between mean of gauss and mean of convolution) is proportional to sigma!
3436 // Thus, choose a reference sigma (typical -> 0.05), such that for arbitrary sigma one can simple scale
3437 // this shift correction with sigma / referenceSigma.
3438 fConvolutedGaussTransitionPars[0] = (fitResGauss->GetParams()[1] - muInput);
3441 /*Changed on 03.07.2013
3443 // Maximum of fConvolutedGausDeltaPrime should agree with maximum of input
3444 Double_t par[nPar] = { fitResGauss->GetParams()[1], // just as a guess of the maximum position
3448 fConvolutedGausDeltaPrime->SetParameters(par);
3450 Double_t maxXInput = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, muInput - 3. * sigmaInput),
3451 muInput + 10. * sigmaInput,
3454 // Maximum shifts proportional to sigma and is linear in mu (~mean of gauss)
3455 // Maximum should be typically located within [gaussMean, gaussMean + 3 gaussSigma].
3456 // -> Larger search range for safety reasons (also: sigma and/or mean might be not 100% accurate).
3457 Double_t maxXconvoluted = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001,
3458 fitResGauss->GetParams()[1] - 3. * fitResGauss->GetParams()[2]),
3459 fitResGauss->GetParams()[1] + 10. * fitResGauss->GetParams()[2],
3461 if (maxXconvoluted <= 0) {
3462 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Maximum of fConvolutedGausDeltaPrime <= 0!\n");
3464 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3465 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3466 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3469 delete [] oldFuncParams;
3474 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX to input value.
3475 // Mu shift correction:
3476 fConvolutedGaussTransitionPars[0] = maxXconvoluted - maxXInput;
3481 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3482 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3483 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3486 delete [] oldFuncParams;
3492 //_____________________________________________________________________________
3493 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::SetParamsForConvolutedGaus(Double_t gausMean, Double_t gausSigma)
3495 // Set parameters for convoluted gauss using parameters for a pure gaussian.
3496 // If SetConvolutedGaussLambdaParameter has not been called before to initialise the translation parameters,
3497 // some default parameters will be used and an error will show up.
3500 printf("File: %s, Line: %d: SetParamsForConvolutedGaus: mean %e, sigma %e\n", (char*)__FILE__, __LINE__, gausMean, gausSigma);
3502 if (fConvolutedGaussTransitionPars[1] < -998) {
3503 AliError("Transition parameters not initialised! Default parameters will be used. Please call SetConvolutedGaussLambdaParameter(...) before any calculations!");
3504 SetConvolutedGaussLambdaParameter(2.0);
3505 AliError(Form("Parameters set to:\n[0]: %f\n[1]: %f\n[2]: %f\n", fConvolutedGaussTransitionPars[0],
3506 fConvolutedGaussTransitionPars[1], fConvolutedGaussTransitionPars[2]));
3509 Double_t par[fkConvolutedGausNPar];
3510 par[2] = fConvolutedGaussTransitionPars[2];
3511 par[1] = fConvolutedGaussTransitionPars[1] * gausSigma;
3512 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX so that it sits at the right place.
3513 par[0] = gausMean - fConvolutedGaussTransitionPars[0] * par[1] / fgkSigmaReferenceForTransitionPars;
3515 ErrorCode errCode = kNoErrors;
3516 fConvolutedGausDeltaPrime->SetParameters(par);
3519 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> Parameters set to: %e, %e, %e (transition pars: %e, %e, %e, %e)\n",
3520 (char*)__FILE__, __LINE__, par[0], par[1], par[2], fConvolutedGaussTransitionPars[0], fConvolutedGaussTransitionPars[1],
3521 fConvolutedGaussTransitionPars[2], fgkSigmaReferenceForTransitionPars);
3523 fConvolutedGausDeltaPrime->SetNpx(20); // Small value speeds up following algorithm (valid, since extrema far apart)
3525 // Accuracy of 10^-5 is enough to get 0.1% precise peak for MIPS w.r.t. to dEdx = 2000 of protons
3526 // (should boost up the algorithm, because 10^-10 is the default value!)
3527 Double_t maxX= fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, gausMean - 2. * gausSigma),
3528 gausMean + 6. * gausSigma, 1.0E-5);
3530 const Double_t maximum = fConvolutedGausDeltaPrime->Eval(maxX);
3531 const Double_t maximumFraction = maximum * fAccuracyNonGaussianTail;
3533 // Estimate lower boundary for subsequent search:
3534 Double_t lowBoundSearchBoundLow = TMath::Max(1e-4, maxX - 5. * gausSigma);
3535 Double_t lowBoundSearchBoundUp = maxX;
3537 Bool_t lowerBoundaryFixedAtZero = kFALSE;
3539 while (fConvolutedGausDeltaPrime->Eval(lowBoundSearchBoundLow) >= maximumFraction) {
3540 if (lowBoundSearchBoundLow <= 0) {
3541 // This should only happen to low dEdx particles with very few clusters and therefore large sigma, such that the gauss goes below zero deltaPrime
3542 if (maximum <= 0) { // Something is weired
3543 printf("Error generating signal: maximum is <= 0!\n");
3547 const Double_t valueAtZero = fConvolutedGausDeltaPrime->Eval(0);
3548 if (valueAtZero / maximum > 0.05) {
3549 // Too large fraction below zero deltaPrime. Signal generation cannot be reliable in this case
3550 printf("Error generating signal: Too large fraction below zero deltaPrime: convGauss(0) / convGauss(max) = %e / %e = %e!\n",
3551 valueAtZero, maximum, valueAtZero / maximum);
3557 printf("Warning: LowBoundSearchBoundLow gets smaller zero -> Set left boundary to zero! Debug output: maximumFraction * fAccuracyNonGaussianTail = %e * %e = %e maxX %f, par[0] %f, par[1] %f, par[2] %f, gausMean %f, gausSigma %f\n",
3558 fConvolutedGausDeltaPrime->Eval(maxX), fAccuracyNonGaussianTail, maximumFraction, maxX, par[0], par[1], par[2], gausMean, gausSigma);
3561 lowerBoundaryFixedAtZero = kTRUE;
3563 if (errCode != kError)
3569 lowBoundSearchBoundUp -= gausSigma;
3570 lowBoundSearchBoundLow -= gausSigma;
3572 if (lowBoundSearchBoundLow < 0) {
3573 lowBoundSearchBoundLow = 0;
3574 lowBoundSearchBoundUp += gausSigma;
3578 // Determine lower boundary inside estimated range. For small values of the maximum: Need more precision, since finer binning!
3579 Double_t rangeStart = lowerBoundaryFixedAtZero ? 0 :
3580 fConvolutedGausDeltaPrime->GetX(maximumFraction, lowBoundSearchBoundLow, lowBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3582 // .. and the same for the upper boundary
3583 Double_t rangeEnd = 0;
3584 // If distribution starts beyond upper boundary, everything ends up in the overflow bin. So, just reduce range and Npx to minimum
3585 if (rangeStart > fkDeltaPrimeUpLimit) {
3586 rangeEnd = rangeStart + 0.00001;
3587 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3588 fConvolutedGausDeltaPrime->SetNpx(4);
3591 // Estimate upper boundary for subsequent search:
3592 Double_t upBoundSearchBoundUp = maxX + 5 * gausSigma;
3593 Double_t upBoundSearchBoundLow = maxX;
3594 while (fConvolutedGausDeltaPrime->Eval(upBoundSearchBoundUp) >= maximumFraction) {
3595 upBoundSearchBoundUp += gausSigma;
3596 upBoundSearchBoundLow += gausSigma;
3599 // For small values of the maximum: Need more precision, since finer binning!
3600 rangeEnd = fConvolutedGausDeltaPrime->GetX(maximumFraction, upBoundSearchBoundLow, upBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3602 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3603 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3605 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3606 //fConvolutedGausDeltaPrime->SetNpx(fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeEnd)
3607 // - fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeStart) + 1);
3608 //fConvolutedGausDeltaPrime->SetNpx((rangeEnd - rangeStart) / fDeltaPrimeBinWidth + 1);
3612 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> range %f - %f, error code %d\n", (char*)__FILE__, __LINE__,
3613 rangeStart, rangeEnd, errCode);
3619 //________________________________________________________________________
3620 void AliAnalysisTaskPID::SetUpGenHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3622 // Sets bin limits for axes which are not standard binned and the axes titles.
3624 hist->SetBinEdges(kGenPt, binsPt);
3625 hist->SetBinEdges(kGenDeltaPrimeSpecies, binsDeltaPrime);
3626 hist->SetBinEdges(kGenCentrality, binsCent);
3628 if (fStoreAdditionalJetInformation)
3629 hist->SetBinEdges(kGenJetPt, binsJetPt);
3632 hist->GetAxis(kGenMCID)->SetTitle("MC PID");
3633 hist->GetAxis(kGenMCID)->SetBinLabel(1, "e");
3634 hist->GetAxis(kGenMCID)->SetBinLabel(2, "K");
3635 hist->GetAxis(kGenMCID)->SetBinLabel(3, "#mu");
3636 hist->GetAxis(kGenMCID)->SetBinLabel(4, "#pi");
3637 hist->GetAxis(kGenMCID)->SetBinLabel(5, "p");
3639 hist->GetAxis(kGenSelectSpecies)->SetTitle("Select Species");
3640 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(1, "e");
3641 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(2, "K");
3642 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(3, "#pi");
3643 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(4, "p");
3645 hist->GetAxis(kGenPt)->SetTitle("p_{T} (GeV/c)");
3647 hist->GetAxis(kGenDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3649 hist->GetAxis(kGenCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3651 if (fStoreAdditionalJetInformation) {
3652 hist->GetAxis(kGenJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3654 hist->GetAxis(kGenZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3656 hist->GetAxis(kGenXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3659 hist->GetAxis(GetIndexOfChargeAxisGen())->SetTitle("Charge (e_{0})");
3661 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetTitle("TOF PID Info");
3662 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3663 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3664 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3665 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3666 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3667 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3671 //________________________________________________________________________
3672 void AliAnalysisTaskPID::SetUpGenYieldHist(THnSparse* hist, Double_t* binsPt, Double_t* binsCent, Double_t* binsJetPt) const
3674 // Sets bin limits for axes which are not standard binned and the axes titles.
3676 hist->SetBinEdges(kGenYieldPt, binsPt);
3677 hist->SetBinEdges(kGenYieldCentrality, binsCent);
3678 if (fStoreAdditionalJetInformation)
3679 hist->SetBinEdges(kGenYieldJetPt, binsJetPt);
3681 for (Int_t i = 0; i < 5; i++)
3682 hist->GetAxis(kGenYieldMCID)->SetBinLabel(i + 1, AliPID::ParticleLatexName(i));
3685 hist->GetAxis(kGenYieldMCID)->SetTitle("MC PID");
3686 hist->GetAxis(kGenYieldPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3687 hist->GetAxis(kGenYieldCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3689 if (fStoreAdditionalJetInformation) {
3690 hist->GetAxis(kGenYieldJetPt)->SetTitle("p_{T}^{jet, gen} (GeV/c)");
3692 hist->GetAxis(kGenYieldZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3694 hist->GetAxis(kGenYieldXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3697 hist->GetAxis(GetIndexOfChargeAxisGenYield())->SetTitle("Charge (e_{0})");
3701 //________________________________________________________________________
3702 void AliAnalysisTaskPID::SetUpHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3704 // Sets bin limits for axes which are not standard binned and the axes titles.
3706 hist->SetBinEdges(kDataPt, binsPt);
3707 hist->SetBinEdges(kDataDeltaPrimeSpecies, binsDeltaPrime);
3708 hist->SetBinEdges(kDataCentrality, binsCent);
3710 if (fStoreAdditionalJetInformation)
3711 hist->SetBinEdges(kDataJetPt, binsJetPt);
3714 hist->GetAxis(kDataMCID)->SetTitle("MC PID");
3715 hist->GetAxis(kDataMCID)->SetBinLabel(1, "e");
3716 hist->GetAxis(kDataMCID)->SetBinLabel(2, "K");
3717 hist->GetAxis(kDataMCID)->SetBinLabel(3, "#mu");
3718 hist->GetAxis(kDataMCID)->SetBinLabel(4, "#pi");
3719 hist->GetAxis(kDataMCID)->SetBinLabel(5, "p");
3721 hist->GetAxis(kDataSelectSpecies)->SetTitle("Select Species");
3722 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(1, "e");
3723 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(2, "K");
3724 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(3, "#pi");
3725 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(4, "p");
3727 hist->GetAxis(kDataPt)->SetTitle("p_{T} (GeV/c)");
3729 hist->GetAxis(kDataDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3731 hist->GetAxis(kDataCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3733 if (fStoreAdditionalJetInformation) {
3734 hist->GetAxis(kDataJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3736 hist->GetAxis(kDataZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3738 hist->GetAxis(kDataXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3741 hist->GetAxis(GetIndexOfChargeAxisData())->SetTitle("Charge (e_{0})");
3743 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetTitle("TOF PID Info");
3744 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3745 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3746 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3747 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3748 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3749 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3753 //________________________________________________________________________
3754 void AliAnalysisTaskPID::SetUpPtResHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt, Double_t* binsCent) const
3756 // Sets bin limits for axes which are not standard binned and the axes titles.
3758 hist->SetBinEdges(kPtResJetPt, binsJetPt);
3759 hist->SetBinEdges(kPtResGenPt, binsPt);
3760 hist->SetBinEdges(kPtResRecPt, binsPt);
3761 hist->SetBinEdges(kPtResCentrality, binsCent);
3764 hist->GetAxis(kPtResJetPt)->SetTitle("p_{T}^{jet, rec} (GeV/c)");
3765 hist->GetAxis(kPtResGenPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3766 hist->GetAxis(kPtResRecPt)->SetTitle("p_{T}^{rec} (GeV/c)");
3768 hist->GetAxis(kPtResCharge)->SetTitle("Charge (e_{0})");
3769 hist->GetAxis(kPtResCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3773 //________________________________________________________________________
3774 void AliAnalysisTaskPID::SetUpSharedClsHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt) const
3776 // Sets bin limits for axes which are not standard binned and the axes titles.
3778 hist->SetBinEdges(kQASharedClsJetPt, binsJetPt);
3779 hist->SetBinEdges(kQASharedClsPt, binsPt);
3782 hist->GetAxis(kQASharedClsJetPt)->SetTitle("#it{p}_{T}^{jet} (GeV/#it{c})");
3783 hist->GetAxis(kQASharedClsPt)->SetTitle("#it{p}_{T} (GeV/#it{c})");
3784 hist->GetAxis(kQASharedClsNumSharedCls)->SetTitle("#it{N}_{shared}^{cls}");
3785 hist->GetAxis(kQASharedClsPadRow)->SetTitle("Pad row");
3790 //________________________________________________________________________
3791 void AliAnalysisTaskPID::SetUpDeDxCheckHist(THnSparse* hist, const Double_t* binsPt, const Double_t* binsJetPt, const Double_t* binsEtaAbs) const
3793 // Sets bin limits for axes which are not standard binned and the axes titles.
3794 hist->SetBinEdges(kDeDxCheckP, binsPt);
3795 hist->SetBinEdges(kDeDxCheckJetPt, binsJetPt);
3796 hist->SetBinEdges(kDeDxCheckEtaAbs, binsEtaAbs);
3800 hist->GetAxis(kDeDxCheckPID)->SetTitle("PID");
3801 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(1, "e");
3802 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(2, "K");
3803 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(3, "#pi");
3804 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(4, "p");
3807 hist->GetAxis(kDeDxCheckJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3808 hist->GetAxis(kDeDxCheckEtaAbs)->SetTitle("|#eta|");
3809 hist->GetAxis(kDeDxCheckP)->SetTitle("p_{TPC} (GeV/c)");
3810 hist->GetAxis(kDeDxCheckDeDx)->SetTitle("TPC dE/dx (arb. unit)");
3814 //________________________________________________________________________
3815 void AliAnalysisTaskPID::SetUpBinZeroStudyHist(THnSparse* hist, const Double_t* binsCent, const Double_t* binsPt) const
3817 // Sets bin limits for axes which are not standard binned and the axes titles.
3818 hist->SetBinEdges(kBinZeroStudyCentrality, binsCent);
3819 hist->SetBinEdges(kBinZeroStudyGenPt, binsPt);
3822 hist->GetAxis(kBinZeroStudyCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3823 hist->GetAxis(kBinZeroStudyGenEta)->SetTitle("#it{#eta}^{gen}");
3824 hist->GetAxis(kBinZeroStudyGenPt)->SetTitle("#it{p}_{T}^{gen} (GeV/#it{c})");