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)
155 , fOutputContainer(0x0)
158 // default Constructor
160 AliLog::SetClassDebugLevel("AliAnalysisTaskPID", AliLog::kInfo);
162 fConvolutedGausDeltaPrime = new TF1("convolutedGausDeltaPrime", this, &AliAnalysisTaskPID::ConvolutedGaus,
163 fkDeltaPrimeLowLimit, fkDeltaPrimeUpLimit,
164 fkConvolutedGausNPar, "AliAnalysisTaskPID", "ConvolutedGaus");
166 // Set some arbitrary parameteres, such that the function call will not crash
167 // (although it should not be called with these parameters...)
168 fConvolutedGausDeltaPrime->SetParameter(0, 0);
169 fConvolutedGausDeltaPrime->SetParameter(1, 1);
170 fConvolutedGausDeltaPrime->SetParameter(2, 2);
173 // Initialisation of translation parameters is time consuming.
174 // Therefore, default values will only be initialised if they are really needed.
175 // Otherwise, it is left to the user to set the parameter properly.
176 fConvolutedGaussTransitionPars[0] = -999;
177 fConvolutedGaussTransitionPars[1] = -999;
178 fConvolutedGaussTransitionPars[2] = -999;
181 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
182 fFractionHists[i] = 0x0;
183 fFractionSysErrorHists[i] = 0x0;
185 fPtResolution[i] = 0x0;
189 //________________________________________________________________________
190 AliAnalysisTaskPID::AliAnalysisTaskPID(const char *name)
191 : AliAnalysisTaskPIDV0base(name)
193 , fPIDcombined(new AliPIDCombined())
194 , fInputFromOtherTask(kFALSE)
196 , fDoEfficiency(kTRUE)
197 , fDoPtResolution(kFALSE)
198 , fDoDeDxCheck(kFALSE)
199 , fDoBinZeroStudy(kFALSE)
200 , fStoreCentralityPercentile(kFALSE)
201 , fStoreAdditionalJetInformation(kFALSE)
202 , fTakeIntoAccountMuons(kFALSE)
206 , fTPCDefaultPriors(kFALSE)
207 , fUseMCidForGeneration(kTRUE)
208 , fUseConvolutedGaus(kFALSE)
209 , fkConvolutedGausNPar(3)
210 , fAccuracyNonGaussianTail(1e-8)
211 , fkDeltaPrimeLowLimit(0.02)
212 , fkDeltaPrimeUpLimit(40.0)
213 , fConvolutedGausDeltaPrime(0x0)
217 , fPileUpRejectionType(AliAnalysisTaskPIDV0base::kPileUpRejectionOff)
218 , fDoAnySystematicStudiesOnTheExpectedSignal(kFALSE)
219 , fSystematicScalingSplinesThreshold(50.)
220 , fSystematicScalingSplinesBelowThreshold(1.0)
221 , fSystematicScalingSplinesAboveThreshold(1.0)
222 , fSystematicScalingEtaCorrectionMomentumThr(0.35)
223 , fSystematicScalingEtaCorrectionLowMomenta(1.0)
224 , fSystematicScalingEtaCorrectionHighMomenta(1.0)
225 , fSystematicScalingEtaSigmaParaThreshold(250.)
226 , fSystematicScalingEtaSigmaParaBelowThreshold(1.0)
227 , fSystematicScalingEtaSigmaParaAboveThreshold(1.0)
228 , fSystematicScalingMultCorrection(1.0)
229 , fCentralityEstimator("V0M")
236 , fGenRespElDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
237 , fGenRespElDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
238 , fGenRespElDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
239 , fGenRespElDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
240 , fGenRespKaDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
241 , fGenRespKaDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
242 , fGenRespKaDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
243 , fGenRespKaDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
244 , fGenRespPiDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
245 , fGenRespPiDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
246 , fGenRespPiDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
247 , fGenRespPiDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
248 , fGenRespMuDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
249 , fGenRespMuDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
250 , fGenRespMuDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
251 , fGenRespMuDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
252 , fGenRespPrDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
253 , fGenRespPrDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
254 , fGenRespPrDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
255 , fGenRespPrDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
257 , fGenRespElDeltaEl(new Double_t[fgkMaxNumGenEntries])
258 , fGenRespElDeltaKa(new Double_t[fgkMaxNumGenEntries])
259 , fGenRespElDeltaPi(new Double_t[fgkMaxNumGenEntries])
260 , fGenRespElDeltaPr(new Double_t[fgkMaxNumGenEntries])
261 , fGenRespKaDeltaEl(new Double_t[fgkMaxNumGenEntries])
262 , fGenRespKaDeltaKa(new Double_t[fgkMaxNumGenEntries])
263 , fGenRespKaDeltaPi(new Double_t[fgkMaxNumGenEntries])
264 , fGenRespKaDeltaPr(new Double_t[fgkMaxNumGenEntries])
265 , fGenRespPiDeltaEl(new Double_t[fgkMaxNumGenEntries])
266 , fGenRespPiDeltaKa(new Double_t[fgkMaxNumGenEntries])
267 , fGenRespPiDeltaPi(new Double_t[fgkMaxNumGenEntries])
268 , fGenRespPiDeltaPr(new Double_t[fgkMaxNumGenEntries])
269 , fGenRespMuDeltaEl(new Double_t[fgkMaxNumGenEntries])
270 , fGenRespMuDeltaKa(new Double_t[fgkMaxNumGenEntries])
271 , fGenRespMuDeltaPi(new Double_t[fgkMaxNumGenEntries])
272 , fGenRespMuDeltaPr(new Double_t[fgkMaxNumGenEntries])
273 , fGenRespPrDeltaEl(new Double_t[fgkMaxNumGenEntries])
274 , fGenRespPrDeltaKa(new Double_t[fgkMaxNumGenEntries])
275 , fGenRespPrDeltaPi(new Double_t[fgkMaxNumGenEntries])
276 , fGenRespPrDeltaPr(new Double_t[fgkMaxNumGenEntries])
278 , fDeltaPrimeAxis(0x0)
279 , fhMaxEtaVariation(0x0)
280 , fhEventsProcessed(0x0)
281 , fhEventsTriggerSel(0x0)
282 , fhEventsTriggerSelVtxCut(0x0)
283 , fhEventsProcessedNoPileUpRejection(0x0)
284 , fChargedGenPrimariesTriggerSel(0x0)
285 , fChargedGenPrimariesTriggerSelVtxCut(0x0)
286 , fChargedGenPrimariesTriggerSelVtxCutZ(0x0)
287 , fChargedGenPrimariesTriggerSelVtxCutZPileUpRej(0x0)
288 , fhMCgeneratedYieldsPrimaries(0x0)
296 , fOutputContainer(0x0)
301 AliLog::SetClassDebugLevel("AliAnalysisTaskPID", AliLog::kInfo);
303 fConvolutedGausDeltaPrime = new TF1("convolutedGausDeltaPrime", this, &AliAnalysisTaskPID::ConvolutedGaus,
304 fkDeltaPrimeLowLimit, fkDeltaPrimeUpLimit,
305 fkConvolutedGausNPar, "AliAnalysisTaskPID", "ConvolutedGaus");
307 // Set some arbitrary parameteres, such that the function call will not crash
308 // (although it should not be called with these parameters...)
309 fConvolutedGausDeltaPrime->SetParameter(0, 0);
310 fConvolutedGausDeltaPrime->SetParameter(1, 1);
311 fConvolutedGausDeltaPrime->SetParameter(2, 2);
314 // Initialisation of translation parameters is time consuming.
315 // Therefore, default values will only be initialised if they are really needed.
316 // Otherwise, it is left to the user to set the parameter properly.
317 fConvolutedGaussTransitionPars[0] = -999;
318 fConvolutedGaussTransitionPars[1] = -999;
319 fConvolutedGaussTransitionPars[2] = -999;
322 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
323 fFractionHists[i] = 0x0;
324 fFractionSysErrorHists[i] = 0x0;
326 fPtResolution[i] = 0x0;
329 // Define input and output slots here
330 // Input slot #0 works with a TChain
331 DefineInput(0, TChain::Class());
333 DefineOutput(1, TObjArray::Class());
335 DefineOutput(2, AliCFContainer::Class());
337 DefineOutput(3, TObjArray::Class());
341 //________________________________________________________________________
342 AliAnalysisTaskPID::~AliAnalysisTaskPID()
346 CleanupParticleFractionHistos();
348 delete fOutputContainer;
349 fOutputContainer = 0x0;
354 delete fConvolutedGausDeltaPrime;
355 fConvolutedGausDeltaPrime = 0x0;
357 delete fDeltaPrimeAxis;
358 fDeltaPrimeAxis = 0x0;
360 delete [] fGenRespElDeltaPrimeEl;
361 delete [] fGenRespElDeltaPrimeKa;
362 delete [] fGenRespElDeltaPrimePi;
363 delete [] fGenRespElDeltaPrimePr;
365 fGenRespElDeltaPrimeEl = 0x0;
366 fGenRespElDeltaPrimeKa = 0x0;
367 fGenRespElDeltaPrimePi = 0x0;
368 fGenRespElDeltaPrimePr = 0x0;
370 delete [] fGenRespKaDeltaPrimeEl;
371 delete [] fGenRespKaDeltaPrimeKa;
372 delete [] fGenRespKaDeltaPrimePi;
373 delete [] fGenRespKaDeltaPrimePr;
375 fGenRespKaDeltaPrimeEl = 0x0;
376 fGenRespKaDeltaPrimeKa = 0x0;
377 fGenRespKaDeltaPrimePi = 0x0;
378 fGenRespKaDeltaPrimePr = 0x0;
380 delete [] fGenRespPiDeltaPrimeEl;
381 delete [] fGenRespPiDeltaPrimeKa;
382 delete [] fGenRespPiDeltaPrimePi;
383 delete [] fGenRespPiDeltaPrimePr;
385 fGenRespPiDeltaPrimeEl = 0x0;
386 fGenRespPiDeltaPrimeKa = 0x0;
387 fGenRespPiDeltaPrimePi = 0x0;
388 fGenRespPiDeltaPrimePr = 0x0;
390 delete [] fGenRespMuDeltaPrimeEl;
391 delete [] fGenRespMuDeltaPrimeKa;
392 delete [] fGenRespMuDeltaPrimePi;
393 delete [] fGenRespMuDeltaPrimePr;
395 fGenRespMuDeltaPrimeEl = 0x0;
396 fGenRespMuDeltaPrimeKa = 0x0;
397 fGenRespMuDeltaPrimePi = 0x0;
398 fGenRespMuDeltaPrimePr = 0x0;
400 delete [] fGenRespPrDeltaPrimeEl;
401 delete [] fGenRespPrDeltaPrimeKa;
402 delete [] fGenRespPrDeltaPrimePi;
403 delete [] fGenRespPrDeltaPrimePr;
405 fGenRespPrDeltaPrimeEl = 0x0;
406 fGenRespPrDeltaPrimeKa = 0x0;
407 fGenRespPrDeltaPrimePi = 0x0;
408 fGenRespPrDeltaPrimePr = 0x0;
410 delete fhMaxEtaVariation;
411 fhMaxEtaVariation = 0x0;
413 /*OLD with deltaSpecies
414 delete [] fGenRespElDeltaEl;
415 delete [] fGenRespElDeltaKa;
416 delete [] fGenRespElDeltaPi;
417 delete [] fGenRespElDeltaPr;
419 fGenRespElDeltaEl = 0x0;
420 fGenRespElDeltaKa = 0x0;
421 fGenRespElDeltaPi = 0x0;
422 fGenRespElDeltaPr = 0x0;
424 delete [] fGenRespKaDeltaEl;
425 delete [] fGenRespKaDeltaKa;
426 delete [] fGenRespKaDeltaPi;
427 delete [] fGenRespKaDeltaPr;
429 fGenRespKaDeltaEl = 0x0;
430 fGenRespKaDeltaKa = 0x0;
431 fGenRespKaDeltaPi = 0x0;
432 fGenRespKaDeltaPr = 0x0;
434 delete [] fGenRespPiDeltaEl;
435 delete [] fGenRespPiDeltaKa;
436 delete [] fGenRespPiDeltaPi;
437 delete [] fGenRespPiDeltaPr;
439 fGenRespPiDeltaEl = 0x0;
440 fGenRespPiDeltaKa = 0x0;
441 fGenRespPiDeltaPi = 0x0;
442 fGenRespPiDeltaPr = 0x0;
444 delete [] fGenRespMuDeltaEl;
445 delete [] fGenRespMuDeltaKa;
446 delete [] fGenRespMuDeltaPi;
447 delete [] fGenRespMuDeltaPr;
449 fGenRespMuDeltaEl = 0x0;
450 fGenRespMuDeltaKa = 0x0;
451 fGenRespMuDeltaPi = 0x0;
452 fGenRespMuDeltaPr = 0x0;
454 delete [] fGenRespPrDeltaEl;
455 delete [] fGenRespPrDeltaKa;
456 delete [] fGenRespPrDeltaPi;
457 delete [] fGenRespPrDeltaPr;
459 fGenRespPrDeltaEl = 0x0;
460 fGenRespPrDeltaKa = 0x0;
461 fGenRespPrDeltaPi = 0x0;
462 fGenRespPrDeltaPr = 0x0;
467 //________________________________________________________________________
468 void AliAnalysisTaskPID::SetUpPIDcombined()
470 // Initialise the PIDcombined object
472 if (!fDoPID && !fDoDeDxCheck)
476 printf("File: %s, Line: %d: SetUpPIDcombined\n", (char*)__FILE__, __LINE__);
479 AliFatal("No PIDcombined object!\n");
483 fPIDcombined->SetSelectedSpecies(AliPID::kSPECIESC);
484 fPIDcombined->SetEnablePriors(fUsePriors);
486 if (fTPCDefaultPriors)
487 fPIDcombined->SetDefaultTPCPriors();
489 //TODO use individual priors...
491 // Change detector mask (TPC,TOF,ITS)
492 Int_t detectorMask = AliPIDResponse::kDetTPC;
494 // Reject mismatch mask - mismatch only relevant for TOF at the moment - other detectors do not use it
495 Int_t rejectMismatchMask = AliPIDResponse::kDetTPC;
499 detectorMask = detectorMask | AliPIDResponse::kDetITS;
500 rejectMismatchMask = rejectMismatchMask | AliPIDResponse::kDetITS;
503 detectorMask = detectorMask | AliPIDResponse::kDetTOF;
504 rejectMismatchMask = rejectMismatchMask | AliPIDResponse::kDetTOF;
507 fPIDcombined->SetDetectorMask(detectorMask);
508 fPIDcombined->SetRejectMismatchMask(rejectMismatchMask);
511 printf("File: %s, Line: %d: SetUpPIDcombined done\n", (char*)__FILE__, __LINE__);
515 //________________________________________________________________________
516 Bool_t AliAnalysisTaskPID::CalculateMaxEtaVariationMapFromPIDResponse()
518 // Calculate the maximum deviation from unity of the eta correction factors for each row in 1/dEdx(splines)
519 // from the eta correction map of the TPCPIDResponse. The result is stored in fhMaxEtaVariation.
522 AliError("No PID response!");
526 delete fhMaxEtaVariation;
528 const TH2D* hEta = fPIDResponse->GetTPCResponse().GetEtaCorrMap();
530 AliError("No eta correction map!");
534 // Take binning from hEta in Y for fhMaxEtaVariation
535 fhMaxEtaVariation = hEta->ProjectionY("hMaxEtaVariation");
536 fhMaxEtaVariation->SetDirectory(0);
537 fhMaxEtaVariation->Reset();
539 // For each bin in 1/dEdx, loop of all tanTheta bins and find the maximum deviation from unity.
540 // Store the result in fhMaxEtaVariation
542 for (Int_t binY = 1; binY <= fhMaxEtaVariation->GetNbinsX(); binY++) {
543 Double_t maxAbs = -1;
544 for (Int_t binX = 1; binX <= hEta->GetNbinsX(); binX++) {
545 Double_t curr = TMath::Abs(hEta->GetBinContent(binX, binY) - 1.);
550 if (maxAbs < 1e-12) {
551 AliError(Form("Maximum deviation from unity is zero for 1/dEdx = %f (bin %d)", hEta->GetYaxis()->GetBinCenter(binY), binY));
552 delete fhMaxEtaVariation;
556 fhMaxEtaVariation->SetBinContent(binY, maxAbs);
559 printf("AliAnalysisTaskPID: Calculated max eta variation from map \"%s\".\n", hEta->GetTitle());
565 //________________________________________________________________________
566 void AliAnalysisTaskPID::UserCreateOutputObjects()
572 printf("File: %s, Line: %d: UserCreateOutputObjects\n", (char*)__FILE__, __LINE__);
574 // Setup basic things, like PIDResponse
575 AliAnalysisTaskPIDV0base::UserCreateOutputObjects();
578 AliFatal("PIDResponse object was not created");
585 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(1) successful\n", (char*)__FILE__, __LINE__);
587 fOutputContainer = new TObjArray(1);
588 fOutputContainer->SetName(GetName());
589 fOutputContainer->SetOwner(kTRUE);
591 const Int_t nPtBins = 68;
592 Double_t binsPt[nPtBins+1] = {0. , 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45,
593 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95,
594 1.0, 1.1 , 1.2, 1.3 , 1.4, 1.5 , 1.6, 1.7 , 1.8, 1.9 ,
595 2.0, 2.2 , 2.4, 2.6 , 2.8, 3.0 , 3.2, 3.4 , 3.6, 3.8 ,
596 4.0, 4.5 , 5.0, 5.5 , 6.0, 6.5 , 7.0, 8.0 , 9.0, 10.0,
597 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0,
598 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0 };
600 const Int_t nCentBins = 12;
601 //-1 for pp (unless explicitely requested); 90-100 has huge electro-magnetic impurities
602 Double_t binsCent[nCentBins+1] = {-1, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
604 // This centrality estimator deals with integers! This implies that the ranges are always [lowlim, uplim - 1]
605 Double_t binsCentITSTPCTracklets[nCentBins+1] = { 0, 7, 13, 20, 29, 40, 50, 60, 72, 83, 95, 105, 115 };
607 // Special centrality binning for pp
608 Double_t binsCentpp[nCentBins+1] = { 0, 0.01, 0.1, 1, 5, 10, 15, 20, 30, 40, 50, 70, 100};
610 if (fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0 && fStoreCentralityPercentile) {
611 // Special binning for this centrality estimator; but keep number of bins!
612 for (Int_t i = 0; i < nCentBins+1; i++)
613 binsCent[i] = binsCentITSTPCTracklets[i];
615 else if (fCentralityEstimator.Contains("ppMult", TString::kIgnoreCase) && fStoreCentralityPercentile) {
616 // Special binning for this pp centrality estimator; but keep number of bins!
617 for (Int_t i = 0; i < nCentBins+1; i++)
618 binsCent[i] = binsCentpp[i];
621 const Int_t nJetPtBins = 11;
622 Double_t binsJetPt[nJetPtBins+1] = {0, 2, 5, 10, 15, 20, 30, 40, 60, 80, 120, 200};
624 const Int_t nChargeBins = 2;
625 const Double_t binsCharge[nChargeBins+1] = { -1.0 - 1e-4, 0.0, 1.0 + 1e-4 };
627 const Int_t nBinsJets = kDataNumAxes;
628 const Int_t nBinsNoJets = nBinsJets - fgkNumJetAxes;
630 const Int_t nBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
632 // deltaPrimeSpecies binning
633 const Int_t deltaPrimeNBins = 600;
634 Double_t deltaPrimeBins[deltaPrimeNBins + 1];
636 const Double_t fromLow = fkDeltaPrimeLowLimit;
637 const Double_t toHigh = fkDeltaPrimeUpLimit;
638 const Double_t factor = TMath::Power(toHigh/fromLow, 1./deltaPrimeNBins);
640 // Log binning for whole deltaPrime range
641 deltaPrimeBins[0] = fromLow;
642 for (Int_t i = 0 + 1; i <= deltaPrimeNBins; i++) {
643 deltaPrimeBins[i] = factor * deltaPrimeBins[i - 1];
646 fDeltaPrimeAxis = new TAxis(deltaPrimeNBins, deltaPrimeBins);
648 const Int_t nMCPIDbins = 5;
649 const Double_t mcPIDmin = 0.;
650 const Double_t mcPIDmax = 5.;
652 const Int_t nSelSpeciesBins = 4;
653 const Double_t selSpeciesMin = 0.;
654 const Double_t selSpeciesMax = 4.;
656 const Int_t nZBins = 20;
657 const Double_t zMin = 0.;
658 const Double_t zMax = 1.;
660 const Int_t nXiBins = 70;
661 const Double_t xiMin = 0.;
662 const Double_t xiMax = 7.;
664 const Int_t nTOFpidInfoBins = kNumTOFpidInfoBins;
665 const Double_t tofPIDinfoMin = kNoTOFinfo;
666 const Double_t tofPIDinfoMax = kNoTOFinfo + kNumTOFpidInfoBins;
668 // MC PID, SelectSpecies, pT, deltaPrimeSpecies, centrality percentile, jet pT, z = track_pT/jet_pT, xi = log(1/z)
669 Int_t binsNoJets[nBinsNoJets] = { nMCPIDbins,
677 Int_t binsJets[nBinsJets] = { nMCPIDbins,
688 Int_t *bins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
690 Double_t xminNoJets[nBinsNoJets] = { mcPIDmin,
698 Double_t xminJets[nBinsJets] = { mcPIDmin,
709 Double_t *xmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
711 Double_t xmaxNoJets[nBinsNoJets] = { mcPIDmax,
714 deltaPrimeBins[deltaPrimeNBins],
716 binsCharge[nChargeBins],
719 Double_t xmaxJets[nBinsJets] = { mcPIDmax,
722 deltaPrimeBins[deltaPrimeNBins],
724 binsJetPt[nJetPtBins],
727 binsCharge[nChargeBins],
730 Double_t *xmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
732 fConvolutedGausDeltaPrime->SetNpx(deltaPrimeNBins);
735 fhPIDdataAll = new THnSparseD("hPIDdataAll","", nBins, bins, xmin, xmax);
736 SetUpHist(fhPIDdataAll, binsPt, deltaPrimeBins, binsCent, binsJetPt);
737 fOutputContainer->Add(fhPIDdataAll);
740 // Generated histograms (so far, bins are the same as for primary THnSparse)
741 const Int_t nGenBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
742 // MC PID, SelectSpecies, Pt, deltaPrimeSpecies, jet pT, z = track_pT/jet_pT, xi = log(1/z)
744 Int_t *genBins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
745 Double_t *genXmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
746 Double_t *genXmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
749 fhGenEl = new THnSparseD("hGenEl", "", nGenBins, genBins, genXmin, genXmax);
750 SetUpGenHist(fhGenEl, binsPt, deltaPrimeBins, binsCent, binsJetPt);
751 fOutputContainer->Add(fhGenEl);
753 fhGenKa = new THnSparseD("hGenKa", "", nGenBins, genBins, genXmin, genXmax);
754 SetUpGenHist(fhGenKa, binsPt, deltaPrimeBins, binsCent, binsJetPt);
755 fOutputContainer->Add(fhGenKa);
757 fhGenPi = new THnSparseD("hGenPi", "", nGenBins, genBins, genXmin, genXmax);
758 SetUpGenHist(fhGenPi, binsPt, deltaPrimeBins, binsCent, binsJetPt);
759 fOutputContainer->Add(fhGenPi);
761 if (fTakeIntoAccountMuons) {
762 fhGenMu = new THnSparseD("hGenMu", "", nGenBins, genBins, genXmin, genXmax);
763 SetUpGenHist(fhGenMu, binsPt, deltaPrimeBins, binsCent, binsJetPt);
764 fOutputContainer->Add(fhGenMu);
767 fhGenPr = new THnSparseD("hGenPr", "", nGenBins, genBins, genXmin, genXmax);
768 SetUpGenHist(fhGenPr, binsPt, deltaPrimeBins, binsCent, binsJetPt);
769 fOutputContainer->Add(fhGenPr);
773 fhEventsProcessed = new TH1D("fhEventsProcessed",
774 "Number of events passing trigger selection, vtx and zvtx cuts and pile-up rejection;Centrality Percentile",
775 nCentBins, binsCent);
776 fhEventsProcessed->Sumw2();
777 fOutputContainer->Add(fhEventsProcessed);
779 fhEventsTriggerSelVtxCut = new TH1D("fhEventsTriggerSelVtxCut",
780 "Number of events passing trigger selection and vtx cut;Centrality Percentile",
781 nCentBins, binsCent);
782 fhEventsTriggerSelVtxCut->Sumw2();
783 fOutputContainer->Add(fhEventsTriggerSelVtxCut);
785 fhEventsTriggerSel = new TH1D("fhEventsTriggerSel",
786 "Number of events passing trigger selection;Centrality Percentile",
787 nCentBins, binsCent);
788 fOutputContainer->Add(fhEventsTriggerSel);
789 fhEventsTriggerSel->Sumw2();
792 fhEventsProcessedNoPileUpRejection = new TH1D("fhEventsProcessedNoPileUpRejection",
793 "Number of events passing trigger selection, vtx and zvtx cuts;Centrality Percentile",
794 nCentBins, binsCent);
795 fOutputContainer->Add(fhEventsProcessedNoPileUpRejection);
796 fhEventsProcessedNoPileUpRejection->Sumw2();
799 // Generated yields within acceptance
800 const Int_t nBinsGenYields = fStoreAdditionalJetInformation ? kGenYieldNumAxes : kGenYieldNumAxes - 3;
801 Int_t genYieldsBins[kGenYieldNumAxes] = { nMCPIDbins, nPtBins, nCentBins, nJetPtBins, nZBins, nXiBins,
803 genYieldsBins[GetIndexOfChargeAxisGenYield()] = nChargeBins;
804 Double_t genYieldsXmin[kGenYieldNumAxes] = { mcPIDmin, binsPt[0], binsCent[0], binsJetPt[0], zMin, xiMin,
806 genYieldsXmin[GetIndexOfChargeAxisGenYield()] = binsCharge[0];
807 Double_t genYieldsXmax[kGenYieldNumAxes] = { mcPIDmax, binsPt[nPtBins], binsCent[nCentBins], binsJetPt[nJetPtBins], zMax, xiMax,
808 binsCharge[nChargeBins] };
809 genYieldsXmax[GetIndexOfChargeAxisGenYield()] = binsCharge[nChargeBins];
812 fhMCgeneratedYieldsPrimaries = new THnSparseD("fhMCgeneratedYieldsPrimaries",
813 "Generated yields w/o reco and cuts inside acceptance (physical primaries)",
814 nBinsGenYields, genYieldsBins, genYieldsXmin, genYieldsXmax);
815 SetUpGenYieldHist(fhMCgeneratedYieldsPrimaries, binsPt, binsCent, binsJetPt);
816 fOutputContainer->Add(fhMCgeneratedYieldsPrimaries);
819 // Container with several process steps (generated and reconstructed level with some variations)
824 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(2) successful\n", (char*)__FILE__, __LINE__);
826 // Array for the number of bins in each dimension
827 // Dimensions: MC-ID, trackPt, trackEta, trackCharge, cenrality percentile, jetPt, z, xi TODO phi???
828 const Int_t nEffDims = fStoreAdditionalJetInformation ? kEffNumAxes : kEffNumAxes - 3; // Number of dimensions for the efficiency
830 const Int_t nMCIDbins = AliPID::kSPECIES;
831 Double_t binsMCID[nMCIDbins + 1];
833 for(Int_t i = 0; i <= nMCIDbins; i++) {
837 const Int_t nEtaBins = 18;
838 const Double_t binsEta[nEtaBins+1] = {-0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
839 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };
841 const Int_t nEffBins[kEffNumAxes] = { nMCIDbins, nPtBins, nEtaBins, nChargeBins, nCentBins, nJetPtBins, nZBins, nXiBins };
843 fContainerEff = new AliCFContainer("containerEff", "Reconstruction Efficiency x Acceptance x Resolution and Secondary Correction",
844 kNumSteps, nEffDims, nEffBins);
846 // Setting the bin limits
847 fContainerEff->SetBinLimits(kEffMCID, binsMCID);
848 fContainerEff->SetBinLimits(kEffTrackPt, binsPt);
849 fContainerEff->SetBinLimits(kEffTrackEta, binsEta);
850 fContainerEff->SetBinLimits(kEffTrackCharge, binsCharge);
851 fContainerEff->SetBinLimits(kEffCentrality, binsCent);
852 if (fStoreAdditionalJetInformation) {
853 fContainerEff->SetBinLimits(kEffJetPt, binsJetPt);
854 fContainerEff->SetBinLimits(kEffZ, zMin, zMax);
855 fContainerEff->SetBinLimits(kEffXi, xiMin, xiMax);
858 fContainerEff->SetVarTitle(kEffMCID,"MC ID");
859 fContainerEff->SetVarTitle(kEffTrackPt,"p_{T} (GeV/c)");
860 fContainerEff->SetVarTitle(kEffTrackEta,"#eta");
861 fContainerEff->SetVarTitle(kEffTrackCharge,"Charge (e_{0})");
862 fContainerEff->SetVarTitle(kEffCentrality, "Centrality Percentile");
863 if (fStoreAdditionalJetInformation) {
864 fContainerEff->SetVarTitle(kEffJetPt, "p_{T}^{jet} (GeV/c)");
865 fContainerEff->SetVarTitle(kEffZ, "z = p_{T}^{track} / p_{T}^{jet}");
866 fContainerEff->SetVarTitle(kEffXi, "#xi = ln(p_{T}^{jet} / p_{T}^{track})");
869 // Define clean MC sample
870 fContainerEff->SetStepTitle(kStepGenWithGenCuts, "Particle level, cuts on particle level");
871 // For Acceptance x Efficiency correction of primaries
872 fContainerEff->SetStepTitle(kStepRecWithGenCuts, "Detector level (rec) with cuts on particle level");
873 // For (pT) resolution correction
874 fContainerEff->SetStepTitle(kStepRecWithGenCutsMeasuredObs,
875 "Detector level (rec) with cuts on particle level with measured observables");
876 // For secondary correction
877 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObs,
878 "Detector level, all cuts on detector level with measured observables");
879 fContainerEff->SetStepTitle(kStepRecWithRecCutsPrimaries,
880 "Detector level, all cuts on detector level, only MC primaries");
881 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsPrimaries,
882 "Detector level, all cuts on detector level with measured observables, only MC primaries");
883 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsStrangenessScaled,
884 "Detector level (strangeness scaled), all cuts on detector level with measured observables");
887 if (fDoPID || fDoEfficiency) {
889 fh2FFJetPtRec = new TH2D("fh2FFJetPtRec", "Number of reconstructed jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
890 nCentBins, binsCent, nJetPtBins, binsJetPt);
891 fh2FFJetPtRec->Sumw2();
892 fOutputContainer->Add(fh2FFJetPtRec);
893 fh2FFJetPtGen = new TH2D("fh2FFJetPtGen", "Number of generated jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
894 nCentBins, binsCent, nJetPtBins, binsJetPt);
895 fh2FFJetPtGen->Sumw2();
896 fOutputContainer->Add(fh2FFJetPtGen);
899 // Pythia information
900 fh1Xsec = new TProfile("fh1Xsec", "xsec from pyxsec.root", 1, 0, 1);
902 fh1Xsec->GetXaxis()->SetBinLabel(1, "<#sigma>");
903 fh1Trials = new TH1D("fh1Trials", "trials from pyxsec.root", 1, 0, 1);
905 fh1Trials->GetXaxis()->SetBinLabel(1, "#sum{ntrials}");
907 fOutputContainer->Add(fh1Xsec);
908 fOutputContainer->Add(fh1Trials);
910 if (fDoDeDxCheck || fDoPtResolution) {
912 fQAContainer = new TObjArray(1);
913 fQAContainer->SetName(Form("%s_QA", GetName()));
914 fQAContainer->SetOwner(kTRUE);
917 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(3) successful\n", (char*)__FILE__, __LINE__);
920 if (fDoPtResolution) {
921 const Int_t nPtBinsRes = 100;
922 Double_t pTbinsRes[nPtBinsRes + 1];
924 const Double_t fromLowPtRes = 0.15;
925 const Double_t toHighPtRes = 50.;
926 const Double_t factorPtRes = TMath::Power(toHighPtRes/fromLowPtRes, 1./nPtBinsRes);
927 // Log binning for whole pT range
928 pTbinsRes[0] = fromLowPtRes;
929 for (Int_t i = 0 + 1; i <= nPtBinsRes; i++) {
930 pTbinsRes[i] = factorPtRes * pTbinsRes[i - 1];
933 const Int_t nBinsPtResolution = kPtResNumAxes;
934 Int_t ptResolutionBins[kPtResNumAxes] = { nJetPtBins, nPtBinsRes, nPtBinsRes,
935 nChargeBins, nCentBins };
936 Double_t ptResolutionXmin[kPtResNumAxes] = { binsJetPt[0], pTbinsRes[0], pTbinsRes[0],
937 binsCharge[0], binsCent[0] };
938 Double_t ptResolutionXmax[kPtResNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], pTbinsRes[nPtBinsRes],
939 binsCharge[nChargeBins], binsCent[nCentBins] };
941 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
942 fPtResolution[i] = new THnSparseD(Form("fPtResolution_%s", AliPID::ParticleShortName(i)),
943 Form("Pt resolution for primaries, %s", AliPID::ParticleLatexName(i)),
944 nBinsPtResolution, ptResolutionBins, ptResolutionXmin, ptResolutionXmax);
945 SetUpPtResHist(fPtResolution[i], pTbinsRes, binsJetPt, binsCent);
946 fQAContainer->Add(fPtResolution[i]);
950 // Besides the pT resolution, also perform check on shared clusters
951 const Int_t nBinsQASharedCls = kQASharedClsNumAxes;
952 Int_t qaSharedClsBins[kQASharedClsNumAxes] = { nJetPtBins, nPtBinsRes, 160, 160 };
953 Double_t qaSharedClsXmin[kQASharedClsNumAxes] = { binsJetPt[0], pTbinsRes[0], 0, -1 };
954 Double_t qaSharedClsXmax[kQASharedClsNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], 160, 159 };
956 fQASharedCls = new THnSparseD("fQASharedCls", "QA shared clusters", nBinsQASharedCls, qaSharedClsBins, qaSharedClsXmin, qaSharedClsXmax);
958 SetUpSharedClsHist(fQASharedCls, pTbinsRes, binsJetPt);
959 fQAContainer->Add(fQASharedCls);
965 const Int_t nEtaAbsBins = 9;
966 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 };
968 const Double_t dEdxMin = 20;
969 const Double_t dEdxMax = 110;
970 const Int_t nDeDxBins = (Int_t) ((dEdxMax - dEdxMin) / 0.02);
971 const Int_t nBinsDeDxCheck= kDeDxCheckNumAxes;
972 Int_t dEdxCheckBins[kDeDxCheckNumAxes] = { nSelSpeciesBins, nPtBins, nJetPtBins, nEtaAbsBins, nDeDxBins };
973 Double_t dEdxCheckXmin[kDeDxCheckNumAxes] = { selSpeciesMin, binsPt[0], binsJetPt[0], binsEtaAbs[0], dEdxMin };
974 Double_t dEdxCheckXmax[kDeDxCheckNumAxes] = { selSpeciesMax, binsPt[nPtBins], binsJetPt[nJetPtBins], binsEtaAbs[nEtaAbsBins], dEdxMax };
976 fDeDxCheck = new THnSparseD("fDeDxCheck", "dEdx check", nBinsDeDxCheck, dEdxCheckBins, dEdxCheckXmin, dEdxCheckXmax);
977 SetUpDeDxCheckHist(fDeDxCheck, binsPt, binsJetPt, binsEtaAbs);
978 fQAContainer->Add(fDeDxCheck);
981 if (fDoBinZeroStudy) {
982 const Double_t etaLow = -0.9;
983 const Double_t etaUp = 0.9;
984 const Int_t nEtaBins = 18;
986 const Int_t nBinsBinZeroStudy = kBinZeroStudyNumAxes;
987 Int_t binZeroStudyBins[nBinsBinZeroStudy] = { nCentBins, nPtBins, nEtaBins };
988 Double_t binZeroStudyXmin[nBinsBinZeroStudy] = { binsCent[0], binsPt[0], etaLow };
989 Double_t binZeroStudyXmax[nBinsBinZeroStudy] = { binsCent[nCentBins], binsPt[nPtBins], etaUp };
991 fChargedGenPrimariesTriggerSel = new THnSparseD("fChargedGenPrimariesTriggerSel", "Trigger sel.", nBinsBinZeroStudy, binZeroStudyBins,
992 binZeroStudyXmin, binZeroStudyXmax);
993 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSel, binsCent, binsPt);
994 fOutputContainer->Add(fChargedGenPrimariesTriggerSel);
996 fChargedGenPrimariesTriggerSelVtxCut = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCut", "Vertex cut", nBinsBinZeroStudy,
997 binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
998 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCut, binsCent, binsPt);
999 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCut);
1001 fChargedGenPrimariesTriggerSelVtxCutZ = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCutZ", "Vertex #it{z} cut", nBinsBinZeroStudy,
1002 binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1003 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCutZ, binsCent, binsPt);
1004 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCutZ);
1006 fChargedGenPrimariesTriggerSelVtxCutZPileUpRej = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCutZPileUpRej", "Vertex #it{z} cut",
1007 nBinsBinZeroStudy, binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1008 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCutZPileUpRej, binsCent, binsPt);
1009 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCutZPileUpRej);
1013 printf("File: %s, Line: %d: UserCreateOutputObjects -> Posting output data\n", (char*)__FILE__, __LINE__);
1015 PostData(1, fOutputContainer);
1017 PostData(2, fContainerEff);
1018 if (fDoDeDxCheck || fDoPtResolution)
1019 PostData(3, fQAContainer);
1022 printf("File: %s, Line: %d: UserCreateOutputObjects -> Done\n", (char*)__FILE__, __LINE__);
1026 //________________________________________________________________________
1027 void AliAnalysisTaskPID::UserExec(Option_t *)
1030 // Called for each event
1033 printf("File: %s, Line: %d: UserExec\n", (char*)__FILE__, __LINE__);
1035 // No processing of event, if input is fed in directly from another task
1036 if (fInputFromOtherTask)
1040 printf("File: %s, Line: %d: UserExec -> Processing started\n", (char*)__FILE__, __LINE__);
1042 fEvent = dynamic_cast<AliVEvent*>(InputEvent());
1044 Printf("ERROR: fEvent not available");
1048 ConfigureTaskForCurrentEvent(fEvent);
1050 fMC = dynamic_cast<AliMCEvent*>(MCEvent());
1052 if (!fPIDResponse || !fPIDcombined)
1055 Double_t centralityPercentile = -1;
1056 if (fStoreCentralityPercentile) {
1057 if (fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0) {
1058 // Special pp centrality estimator
1059 AliESDEvent* esdEvent = dynamic_cast<AliESDEvent*>(fEvent);
1061 AliError("Not esd event -> Cannot use tracklet multiplicity estimator!");
1062 centralityPercentile = -1;
1065 centralityPercentile = AliESDtrackCuts::GetReferenceMultiplicity(esdEvent, AliESDtrackCuts::kTrackletsITSTPC, fEtaAbsCutUp);
1067 else if (fCentralityEstimator.Contains("ppMult", TString::kIgnoreCase)) {
1068 // Another special pp centrality estimator
1069 centralityPercentile = fAnaUtils->GetMultiplicityPercentile(fEvent, GetPPCentralityEstimator().Data());
1072 // Ordinary centrality estimator
1073 centralityPercentile = fEvent->GetCentrality()->GetCentralityPercentile(fCentralityEstimator.Data());
1077 // Check if vertex is ok, but don't apply cut on z position
1078 const Bool_t passedVertexSelection = GetVertexIsOk(fEvent, kFALSE);
1079 // Now check again, but also require z position to be in desired range
1080 const Bool_t passedVertexZSelection = GetVertexIsOk(fEvent, kTRUE);
1082 const Bool_t isPileUp = GetIsPileUp(fEvent, fPileUpRejectionType);
1086 if (fDoBinZeroStudy && fMC) {
1087 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1088 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1093 if (!fMC->IsPhysicalPrimary(iPart))
1096 const Double_t etaGen = mcPart->Eta();
1097 const Double_t ptGen = mcPart->Pt();
1099 Double_t values[kBinZeroStudyNumAxes] = { 0. };
1100 values[kBinZeroStudyCentrality] = centralityPercentile;
1101 values[kBinZeroStudyGenPt] = ptGen;
1102 values[kBinZeroStudyGenEta] = etaGen;
1104 fChargedGenPrimariesTriggerSel->Fill(values);
1105 if (passedVertexSelection) {
1106 fChargedGenPrimariesTriggerSelVtxCut->Fill(values);
1107 if (passedVertexZSelection) {
1108 fChargedGenPrimariesTriggerSelVtxCutZ->Fill(values);
1110 fChargedGenPrimariesTriggerSelVtxCutZPileUpRej->Fill(values);
1119 // Event counters for trigger selection, vertex cuts and pile-up rejection
1120 IncrementEventCounter(centralityPercentile, kTriggerSel);
1122 if (!passedVertexSelection)
1125 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCut);
1127 if (!passedVertexZSelection)
1130 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCutNoPileUpRejection);
1131 // ATTENTION: Is this the right place for the pile-up rejection? Important to have still the proper bin-0 correction,
1132 // which is done solely with sel and selVtx, since the zvtx selection does ~not change the spectra. The question is whether the pile-up
1133 // 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
1134 // of events. But if it does change the spectra, this must somehow be corrected for.
1135 // NOTE: multiplicity >= 0 usually implies a properly reconstructed vertex. Hence, the bin-0 correction cannot be done in multiplicity bins.
1136 // Furthermore, there seems to be no MC simulation with pile-up rejection, so the bin-0 correction cannot be extracted with it. Pile-up
1137 // rejection has only a minor impact, so maybe there is no need to dig further.
1141 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCut);
1143 Double_t magField = fEvent->GetMagneticField();
1146 if (fDoPID || fDoEfficiency) {
1147 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1148 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1153 // Define clean MC sample with corresponding particle level track cuts:
1154 // - MC-track must be in desired eta range
1155 // - MC-track must be physical primary
1156 // - Species must be one of those in question (everything else goes to the overflow bin of mcID)
1158 // Geometrie should be the same as on the reconstructed level -> By definition analysis within this eta interval
1159 if (!IsInAcceptedEtaRange(TMath::Abs(mcPart->Eta()))) continue;
1161 Int_t mcID = PDGtoMCID(mcPart->PdgCode());
1163 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1164 Double_t chargeMC = mcPart->Charge() / 3.;
1166 if (TMath::Abs(chargeMC) < 0.01)
1167 continue; // Reject neutral particles (only relevant, if mcID is not used)
1169 if (!fMC->IsPhysicalPrimary(iPart))
1173 Double_t valuesGenYield[kGenYieldNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), centralityPercentile, -1, -1, -1, -1 };
1174 valuesGenYield[GetIndexOfChargeAxisGenYield()] = chargeMC;
1176 fhMCgeneratedYieldsPrimaries->Fill(valuesGenYield);
1180 if (fDoEfficiency) {
1181 Double_t valueEff[kEffNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), mcPart->Eta(), chargeMC, centralityPercentile,
1184 fContainerEff->Fill(valueEff, kStepGenWithGenCuts);
1190 // Track loop to fill a Train spectrum
1191 for (Int_t iTracks = 0; iTracks < fEvent->GetNumberOfTracks(); iTracks++) {
1192 AliVTrack* track = dynamic_cast<AliVTrack*>(fEvent->GetTrack(iTracks));
1194 Printf("ERROR: Could not retrieve track %d", iTracks);
1199 // Apply detector level track cuts
1200 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
1201 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
1202 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
1206 if(fTrackFilter && !fTrackFilter->IsSelected(track))
1209 if (GetUseTPCCutMIGeo()) {
1210 if (!TPCCutMIGeo(track, fEvent))
1213 else if (GetUseTPCnclCut()) {
1214 if (!TPCnclCut(track))
1219 if (!PhiPrimeCut(track, magField))
1220 continue; // reject track
1223 Int_t pdg = 0; // = 0 indicates data for the moment
1224 AliMCParticle* mcTrack = 0x0;
1225 Int_t mcID = AliPID::kUnknown;
1229 label = track->GetLabel();
1234 mcTrack = dynamic_cast<AliMCParticle*>(fMC->GetTrack(TMath::Abs(label)));
1236 Printf("ERROR: Could not retrieve mcTrack with label %d for track %d", label, iTracks);
1240 pdg = mcTrack->PdgCode();
1241 mcID = PDGtoMCID(mcTrack->PdgCode());
1243 if (fDoEfficiency) {
1244 // For efficiency: Reconstructed track has survived all cuts on the detector level (excluding acceptance)
1245 // and has an associated MC track which is a physical primary and was generated inside the acceptance
1246 if (fMC->IsPhysicalPrimary(TMath::Abs(label)) &&
1247 IsInAcceptedEtaRange(TMath::Abs(mcTrack->Eta()))) {
1249 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1250 Double_t value[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3., centralityPercentile,
1252 fContainerEff->Fill(value, kStepRecWithGenCuts);
1254 Double_t valueMeas[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1256 fContainerEff->Fill(valueMeas, kStepRecWithGenCutsMeasuredObs);
1261 // Only process tracks inside the desired eta window
1262 if (!IsInAcceptedEtaRange(TMath::Abs(track->Eta()))) continue;
1264 if (fDoPID || fDoDeDxCheck || fDoPtResolution)
1265 ProcessTrack(track, pdg, centralityPercentile, -1); // No jet information in this case -> Set jet pT to -1
1267 if (fDoPtResolution) {
1268 if (mcTrack && fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1269 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1270 Double_t valuePtRes[kPtResNumAxes] = { -1, mcTrack->Pt(), track->Pt(), mcTrack->Charge() / 3., centralityPercentile };
1271 FillPtResolution(mcID, valuePtRes);
1275 if (fDoEfficiency) {
1277 Double_t valueRecAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1279 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObs);
1281 Double_t weight = IsSecondaryWithStrangeMotherMC(fMC, TMath::Abs(label)) ?
1282 GetMCStrangenessFactorCMS(fMC, mcTrack) : 1.0;
1283 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsStrangenessScaled, weight);
1285 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1286 Double_t valueGenAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3.,
1287 centralityPercentile, -1, -1, -1 };
1288 if (fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1289 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsPrimaries);
1290 fContainerEff->Fill(valueGenAllCuts, kStepRecWithRecCutsPrimaries);
1297 printf("File: %s, Line: %d: UserExec -> Processing done\n", (char*)__FILE__, __LINE__);
1302 printf("File: %s, Line: %d: UserExec -> Done\n", (char*)__FILE__, __LINE__);
1305 //________________________________________________________________________
1306 void AliAnalysisTaskPID::Terminate(const Option_t *)
1308 // Draw result to the screen
1309 // Called once at the end of the query
1313 //_____________________________________________________________________________
1314 void AliAnalysisTaskPID::CheckDoAnyStematicStudiesOnTheExpectedSignal()
1316 // Check whether at least one scale factor indicates the ussage of systematic studies
1317 // and set internal flag accordingly.
1319 fDoAnySystematicStudiesOnTheExpectedSignal = kFALSE;
1322 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
1323 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
1324 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1328 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1329 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1330 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1334 if ((TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
1335 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon)) {
1336 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1340 if (TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
1341 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1347 //_____________________________________________________________________________
1348 void AliAnalysisTaskPID::ConfigureTaskForCurrentEvent(AliVEvent* event)
1350 // Configure the task for the current event. In particular, this is needed if the run number changes
1353 AliError("Could not set up task: no event!");
1357 Int_t run = event->GetRunNumber();
1360 // If systematics on eta is investigated, need to calculate the maxEtaVariationMap
1361 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1362 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1363 if (!CalculateMaxEtaVariationMapFromPIDResponse())
1364 AliFatal("Systematics on eta correction requested, but failed to calculate max eta varation map!");
1372 //_____________________________________________________________________________
1373 Int_t AliAnalysisTaskPID::PDGtoMCID(Int_t pdg)
1375 // Returns the corresponding AliPID index to the given pdg code.
1376 // Returns AliPID::kUnkown if pdg belongs to a not considered species.
1378 Int_t absPDGcode = TMath::Abs(pdg);
1379 if (absPDGcode == 211) {//Pion
1380 return AliPID::kPion;
1382 else if (absPDGcode == 321) {//Kaon
1383 return AliPID::kKaon;
1385 else if (absPDGcode == 2212) {//Proton
1386 return AliPID::kProton;
1388 else if (absPDGcode == 11) {//Electron
1389 return AliPID::kElectron;
1391 else if (absPDGcode == 13) {//Muon
1392 return AliPID::kMuon;
1395 return AliPID::kUnknown;
1399 //_____________________________________________________________________________
1400 void AliAnalysisTaskPID::GetJetTrackObservables(Double_t trackPt, Double_t jetPt, Double_t& z, Double_t& xi)
1402 // Uses trackPt and jetPt to obtain z and xi.
1404 z = (jetPt > 0 && trackPt >= 0) ? (trackPt / jetPt) : -1;
1405 xi = (z > 0) ? TMath::Log(1. / z) : -1;
1407 if(trackPt > (1. - 1e-06) * jetPt && trackPt < (1. + 1e-06) * jetPt) { // case z=1 : move entry to last histo bin <1
1414 //_____________________________________________________________________________
1415 void AliAnalysisTaskPID::CleanupParticleFractionHistos()
1417 // Delete histos with particle fractions
1419 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1420 delete fFractionHists[i];
1421 fFractionHists[i] = 0x0;
1423 delete fFractionSysErrorHists[i];
1424 fFractionSysErrorHists[i] = 0x0;
1429 //_____________________________________________________________________________
1430 Double_t AliAnalysisTaskPID::ConvolutedGaus(const Double_t* xx, const Double_t* par) const
1432 // Convolutes gauss with an exponential tail which describes dEdx-response better than pure gaussian
1434 const Double_t mean = par[0];
1435 const Double_t sigma = par[1];
1436 const Double_t lambda = par[2];
1439 printf("File: %s, Line: %d: ConvolutedGaus: mean %e, sigma %e, lambda %e\n", (char*)__FILE__, __LINE__, mean, sigma, lambda);
1441 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);
1445 //_____________________________________________________________________________
1446 inline Double_t AliAnalysisTaskPID::FastGaus(Double_t x, Double_t mean, Double_t sigma) const
1448 // Calculate an unnormalised gaussian function with mean and sigma.
1450 if (sigma < fgkEpsilon)
1453 const Double_t arg = (x - mean) / sigma;
1454 return exp(-0.5 * arg * arg);
1458 //_____________________________________________________________________________
1459 inline Double_t AliAnalysisTaskPID::FastNormalisedGaus(Double_t x, Double_t mean, Double_t sigma) const
1461 // Calculate a normalised (divided by sqrt(2*Pi)*sigma) gaussian function with mean and sigma.
1463 if (sigma < fgkEpsilon)
1466 const Double_t arg = (x - mean) / sigma;
1467 const Double_t res = exp(-0.5 * arg * arg);
1468 return res / (2.50662827463100024 * sigma); //sqrt(2*Pi)=2.50662827463100024
1472 //_____________________________________________________________________________
1473 Int_t AliAnalysisTaskPID::FindBinWithinRange(TAxis* axis, Double_t value) const
1475 // Find the corresponding bin of the axis. Values outside the range (also under and overflow) will be set to the first/last
1478 Int_t bin = axis->FindFixBin(value);
1482 if (bin > axis->GetNbins())
1483 bin = axis->GetNbins();
1489 //_____________________________________________________________________________
1490 Int_t AliAnalysisTaskPID::FindFirstBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1493 // Kind of projects a TH3 to 1 bin combination in y and z
1494 // and looks for the first x bin above a threshold for this projection.
1495 // If no such bin is found, -1 is returned.
1500 Int_t nBinsX = hist->GetNbinsX();
1501 for (Int_t xBin = 1; xBin <= nBinsX; xBin++) {
1502 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1510 //_____________________________________________________________________________
1511 Int_t AliAnalysisTaskPID::FindLastBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1514 // Kind of projects a TH3 to 1 bin combination in y and z
1515 // and looks for the last x bin above a threshold for this projection.
1516 // If no such bin is found, -1 is returned.
1521 Int_t nBinsX = hist->GetNbinsX();
1522 for (Int_t xBin = nBinsX; xBin >= 1; xBin--) {
1523 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1531 //_____________________________________________________________________________
1532 Bool_t AliAnalysisTaskPID::GetParticleFraction(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1533 AliPID::EParticleType species,
1534 Double_t& fraction, Double_t& fractionErrorStat, Double_t& fractionErrorSys) const
1536 // Computes the particle fraction for the corresponding species for the given trackPt, jetPt and centrality.
1537 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1538 // On success (return value kTRUE), fraction contains the particle fraction, fractionErrorStat(Sys) the sigma of its
1539 // statistical (systematic) error
1542 fractionErrorStat = 999.;
1543 fractionErrorSys = 999.;
1545 if (species > AliPID::kProton || species < AliPID::kElectron) {
1546 AliError(Form("Only fractions for species index %d to %d availabe, but not for the requested one: %d", 0, AliPID::kProton, species));
1550 if (!fFractionHists[species]) {
1551 AliError(Form("Histo with particle fractions for species %d not loaded!", species));
1556 Int_t jetPtBin = FindBinWithinRange(fFractionHists[species]->GetYaxis(), jetPt);
1557 Int_t centBin = FindBinWithinRange(fFractionHists[species]->GetZaxis(), centralityPercentile);
1559 // The following interpolation takes the bin content of the first/last available bin,
1560 // if requested point lies beyond bin center of first/last bin.
1561 // The interpolation is only done for the x-axis (track pT), i.e. jetPtBin and centBin are fix,
1562 // because the analysis will anyhow be run in bins of jetPt and centrality and
1563 // it is not desired to correlate different jetPt bins via interpolation.
1565 // The same procedure is used for the error of the fraction
1566 TAxis* xAxis = fFractionHists[species]->GetXaxis();
1568 // No interpolation to values beyond the centers of the first/last bins (we don't know exactly where the spectra start or stop,
1569 // thus, search for the first and last bin above 0.0 to constrain the range
1570 Int_t firstBin = TMath::Max(1, FindFirstBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1571 Int_t lastBin = TMath::Min(fFractionHists[species]->GetNbinsX(),
1572 FindLastBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1574 if (trackPt <= xAxis->GetBinCenter(firstBin)) {
1575 fraction = fFractionHists[species]->GetBinContent(firstBin, jetPtBin, centBin);
1576 fractionErrorStat = fFractionHists[species]->GetBinError(firstBin, jetPtBin, centBin);
1577 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(firstBin, jetPtBin, centBin) : 0.;
1579 else if (trackPt >= xAxis->GetBinCenter(lastBin)) {
1580 fraction = fFractionHists[species]->GetBinContent(lastBin, jetPtBin, centBin);
1581 fractionErrorStat = fFractionHists[species]->GetBinError(lastBin, jetPtBin, centBin);
1582 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(lastBin, jetPtBin, centBin) : 0.;
1585 Double_t x0 = 0., x1 = 0., y0 = 0., y1 = 0.;
1586 Double_t y0errStat = 0., y1errStat = 0., y0errSys = 0., y1errSys = 0.;
1587 Int_t trackPtBin = xAxis->FindFixBin(trackPt);
1589 // Linear interpolation between nearest neighbours in trackPt
1590 if (trackPt <= xAxis->GetBinCenter(trackPtBin)) {
1591 y0 = fFractionHists[species]->GetBinContent(trackPtBin - 1, jetPtBin, centBin);
1592 y0errStat = fFractionHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin);
1593 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin)
1595 x0 = xAxis->GetBinCenter(trackPtBin - 1);
1596 y1 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1597 y1errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1598 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1600 x1 = xAxis->GetBinCenter(trackPtBin);
1603 y0 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1604 y0errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1605 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1607 x0 = xAxis->GetBinCenter(trackPtBin);
1608 y1 = fFractionHists[species]->GetBinContent(trackPtBin + 1, jetPtBin, centBin);
1609 y1errStat = fFractionHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin);
1610 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin)
1612 x1 = xAxis->GetBinCenter(trackPtBin + 1);
1615 // Per construction: x0 < trackPt < x1
1616 fraction = y0 + (trackPt - x0) * ((y1 - y0) / (x1 - x0));
1617 fractionErrorStat = y0errStat + (trackPt - x0) * ((y1errStat - y0errStat) / (x1 - x0));
1618 fractionErrorSys = fFractionSysErrorHists[species] ? (y0errSys + (trackPt - x0) * ((y1errSys - y0errSys) / (x1 - x0))) : 0.;
1625 //_____________________________________________________________________________
1626 Bool_t AliAnalysisTaskPID::GetParticleFractions(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1627 Double_t* prob, Int_t smearSpeciesByError,
1628 Int_t takeIntoAccountSpeciesSysError, Bool_t uniformSystematicError) const
1630 // Fills the particle fractions for the given trackPt, jetPt and centrality into "prob".
1631 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1632 // If smearSpeciesByError is >= 0 && < AliPID::kSPECIES, the returned fractions will be a random number distributed
1633 // with a gauss with mean being the corresponding particle fraction and sigma it's error for the considered species
1634 // "smearSpeciesByError".
1635 // Note that in this case the fractions for all species will NOT sum up to 1!
1636 // Thus, all other species fractions will be re-scaled weighted with their corresponding statistical error.
1637 // A similar procedure is used for "takeIntoAccountSpeciesSysError": The systematic error of the corresponding species
1638 // is used to generate a random number with uniform distribution in [mean - sysError, mean + sysError] for the new mean
1639 // (in cace of uniformSystematicError = kTRUE, otherwise it will be a gaus(mean, sysError)),
1640 // then the other species will be re-scaled according to their systematic errors.
1641 // First, the systematic error uncertainty procedure will be performed (that is including re-scaling), then the statistical
1642 // uncertainty procedure.
1643 // On success, kTRUE is returned.
1645 if (!prob || smearSpeciesByError >= AliPID::kSPECIES || takeIntoAccountSpeciesSysError >= AliPID::kSPECIES)
1648 Double_t probTemp[AliPID::kSPECIES];
1649 Double_t probErrorStat[AliPID::kSPECIES];
1650 Double_t probErrorSys[AliPID::kSPECIES];
1652 Bool_t success = kTRUE;
1653 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kElectron,
1654 probTemp[AliPID::kElectron], probErrorStat[AliPID::kElectron],
1655 probErrorSys[AliPID::kElectron]);
1656 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kMuon,
1657 probTemp[AliPID::kMuon], probErrorStat[AliPID::kMuon], probErrorSys[AliPID::kMuon]);
1658 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kPion,
1659 probTemp[AliPID::kPion], probErrorStat[AliPID::kPion], probErrorSys[AliPID::kPion]);
1660 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kKaon,
1661 probTemp[AliPID::kKaon], probErrorStat[AliPID::kKaon], probErrorSys[AliPID::kKaon]);
1662 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kProton,
1663 probTemp[AliPID::kProton], probErrorStat[AliPID::kProton], probErrorSys[AliPID::kProton]);
1668 // If desired, take into account the systematic error of the corresponding species and re-generate probTemp accordingly
1669 if (takeIntoAccountSpeciesSysError >= 0) {
1670 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1671 Double_t generatedFraction = uniformSystematicError
1672 ? fRandom->Rndm() * 2. * probErrorSys[takeIntoAccountSpeciesSysError]
1673 - probErrorSys[takeIntoAccountSpeciesSysError]
1674 + probTemp[takeIntoAccountSpeciesSysError]
1675 : fRandom->Gaus(probTemp[takeIntoAccountSpeciesSysError],
1676 probErrorSys[takeIntoAccountSpeciesSysError]);
1678 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1679 if (generatedFraction < 0.)
1680 generatedFraction = 0.;
1681 else if (generatedFraction > 1.)
1682 generatedFraction = 1.;
1684 // Calculate difference from original fraction (original fractions sum up to 1!)
1685 Double_t deltaFraction = generatedFraction - probTemp[takeIntoAccountSpeciesSysError];
1687 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1688 if (deltaFraction > 0) {
1689 // Some part will be SUBTRACTED from the other fractions
1690 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1691 if (probTemp[i] - probErrorSys[i] < 0)
1692 probErrorSys[i] = probTemp[i];
1696 // Some part will be ADDED to the other fractions
1697 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1698 if (probTemp[i] + probErrorSys[i] > 1)
1699 probErrorSys[i] = 1. - probTemp[i];
1703 // Compute summed weight of all fractions except for the considered one
1704 Double_t summedWeight = 0.;
1705 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1706 if (i != takeIntoAccountSpeciesSysError)
1707 summedWeight += probErrorSys[i];
1710 // Compute the weight for the other species
1712 if (summedWeight <= 1e-13) {
1713 // If this happens for some reason (it should not!), just assume flat weight
1714 printf("Error: summedWeight (sys error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1715 trackPt, jetPt, centralityPercentile);
1718 Double_t weight[AliPID::kSPECIES];
1719 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1720 if (i != takeIntoAccountSpeciesSysError) {
1721 if (summedWeight > 1e-13)
1722 weight[i] = probErrorSys[i] / summedWeight;
1724 weight[i] = probErrorSys[i] / (AliPID::kSPECIES - 1);
1728 // For the final generated fractions, set the generated value for the considered species
1729 // and the generated value minus delta times statistical weight
1730 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1731 if (i != takeIntoAccountSpeciesSysError)
1732 probTemp[i] = probTemp[i] - weight[i] * deltaFraction;
1734 probTemp[i] = generatedFraction;
1738 // Using the values of probTemp (either the original ones or those after taking into account the systematic error),
1739 // calculate the final fractions - if the statistical error is to be taken into account, smear the corresponding
1740 // fraction. If not, just write probTemp to the final result array.
1741 if (smearSpeciesByError >= 0) {
1742 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1743 Double_t generatedFraction = fRandom->Gaus(probTemp[smearSpeciesByError], probErrorStat[smearSpeciesByError]);
1745 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1746 if (generatedFraction < 0.)
1747 generatedFraction = 0.;
1748 else if (generatedFraction > 1.)
1749 generatedFraction = 1.;
1751 // Calculate difference from original fraction (original fractions sum up to 1!)
1752 Double_t deltaFraction = generatedFraction - probTemp[smearSpeciesByError];
1754 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1755 if (deltaFraction > 0) {
1756 // Some part will be SUBTRACTED from the other fractions
1757 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1758 if (probTemp[i] - probErrorStat[i] < 0)
1759 probErrorStat[i] = probTemp[i];
1763 // Some part will be ADDED to the other fractions
1764 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1765 if (probTemp[i] + probErrorStat[i] > 1)
1766 probErrorStat[i] = 1. - probTemp[i];
1770 // Compute summed weight of all fractions except for the considered one
1771 Double_t summedWeight = 0.;
1772 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1773 if (i != smearSpeciesByError)
1774 summedWeight += probErrorStat[i];
1777 // Compute the weight for the other species
1779 if (summedWeight <= 1e-13) {
1780 // If this happens for some reason (it should not!), just assume flat weight
1781 printf("Error: summedWeight (stat error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1782 trackPt, jetPt, centralityPercentile);
1785 Double_t weight[AliPID::kSPECIES];
1786 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1787 if (i != smearSpeciesByError) {
1788 if (summedWeight > 1e-13)
1789 weight[i] = probErrorStat[i] / summedWeight;
1791 weight[i] = probErrorStat[i] / (AliPID::kSPECIES - 1);
1795 // For the final generated fractions, set the generated value for the considered species
1796 // and the generated value minus delta times statistical weight
1797 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1798 if (i != smearSpeciesByError)
1799 prob[i] = probTemp[i] - weight[i] * deltaFraction;
1801 prob[i] = generatedFraction;
1805 // Just take the generated values
1806 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
1807 prob[i] = probTemp[i];
1811 // Should already be normalised, but make sure that it really is:
1812 Double_t probSum = 0.;
1813 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1820 if (TMath::Abs(probSum - 1.0) > 1e-4) {
1821 printf("Warning: Re-normalising sum of fractions: Sum is %e\n", probSum);
1822 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1831 //_____________________________________________________________________________
1832 const TH3D* AliAnalysisTaskPID::GetParticleFractionHisto(Int_t species, Bool_t sysError) const
1834 if (species < AliPID::kElectron || species > AliPID::kProton)
1837 return sysError ? fFractionSysErrorHists[species] : fFractionHists[species];
1841 //_____________________________________________________________________________
1842 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(Int_t motherPDG, Double_t motherGenPt)
1844 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1845 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction, which uses
1846 // the following data from CMS pp @ 7 TeV inclusive (JHEP 05 (2011) 064)
1850 const Int_t absMotherPDG = TMath::Abs(motherPDG);
1852 if (absMotherPDG == 310 || absMotherPDG == 321) { // K0s / K+ / K-
1853 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.768049;
1854 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.732933;
1855 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.650298;
1856 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.571332;
1857 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.518734;
1858 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.492543;
1859 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.482704;
1860 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.488056;
1861 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.488861;
1862 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.492862;
1863 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.504332;
1864 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.501858;
1865 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.512970;
1866 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.524131;
1867 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.539130;
1868 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.554101;
1869 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.560348;
1870 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.568869;
1871 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.583310;
1872 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.604818;
1873 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.632630;
1874 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.710070;
1875 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.736365;
1876 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 0.835865;
1879 if (absMotherPDG == 3122) { // Lambda
1880 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.645162;
1881 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.627431;
1882 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.457136;
1883 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.384369;
1884 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.330597;
1885 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.309571;
1886 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.293620;
1887 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.283709;
1888 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.282047;
1889 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.277261;
1890 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.275772;
1891 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.280726;
1892 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.288540;
1893 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.288315;
1894 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.296619;
1895 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.302993;
1896 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.338121;
1897 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.349800;
1898 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.356802;
1899 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.391202;
1900 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.422573;
1901 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.573815;
1902 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.786984;
1903 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 1.020021;
1906 if (absMotherPDG == 3312 || absMotherPDG == 3322) { // xi
1907 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.666620;
1908 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.575908;
1909 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.433198;
1910 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.340901;
1911 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.290896;
1912 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.236074;
1913 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.218681;
1914 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.207763;
1915 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.222848;
1916 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.208806;
1917 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.197275;
1918 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.183645;
1919 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.188788;
1920 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.188282;
1921 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.207442;
1922 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.240388;
1923 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.241916;
1924 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.208276;
1925 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.234550;
1926 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.251689;
1927 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.310204;
1928 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.343492;
1931 const Double_t weight = 1. / fac;
1937 //_____________________________________________________________________________
1938 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(AliMCEvent* mcEvent, AliMCParticle* daughter)
1940 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1941 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction
1946 AliMCParticle* currentMother = daughter;
1947 AliMCParticle* currentDaughter = daughter;
1950 // find first primary mother K0s, Lambda or Xi
1952 Int_t daughterPDG = currentDaughter->PdgCode();
1954 Int_t motherLabel = currentDaughter->GetMother();
1955 if(motherLabel >= mcEvent->GetNumberOfTracks()){ // protection
1956 currentMother = currentDaughter;
1960 currentMother = (AliMCParticle*)mcEvent->GetTrack(motherLabel);
1962 if (!currentMother) {
1963 currentMother = currentDaughter;
1967 Int_t motherPDG = currentMother->PdgCode();
1969 // phys. primary found ?
1970 if (mcEvent->IsPhysicalPrimary(motherLabel))
1973 if (TMath::Abs(daughterPDG) == 321) {
1974 // K+/K- e.g. from phi (ref data not feeddown corrected)
1975 currentMother = currentDaughter;
1978 if (TMath::Abs(motherPDG) == 310) {
1979 // K0s e.g. from phi (ref data not feeddown corrected)
1982 if (TMath::Abs(motherPDG) == 3212 && TMath::Abs(daughterPDG) == 3122) {
1983 // Mother Sigma0, daughter Lambda (this case not included in feeddown corr.)
1984 currentMother = currentDaughter;
1988 currentDaughter = currentMother;
1992 Int_t motherPDG = currentMother->PdgCode();
1993 Double_t motherGenPt = currentMother->Pt();
1995 return GetMCStrangenessFactorCMS(motherPDG, motherGenPt);
1999 // _________________________________________________________________________________
2000 AliAnalysisTaskPID::TOFpidInfo AliAnalysisTaskPID::GetTOFType(const AliVTrack* track, Int_t tofMode) const
2002 // Get the (locally defined) particle type judged by TOF
2004 if (!fPIDResponse) {
2005 Printf("ERROR: fPIDResponse not available -> Cannot determine TOF type!");
2009 /*TODO still needs some further thinking how to implement it....
2010 // TOF PID status (kTOFout, kTIME) automatically checked by return value of ComputeTPCProbability;
2011 // also, probability array will be set there (no need to initialise here)
2012 Double_t p[AliPID::kSPECIES];
2013 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->ComputeTPCProbability(track, AliPID::kSPECIES, p);
2014 if (tofStatus != AliPIDResponse::kDetPidOk)
2017 // Do not consider muons
2018 p[AliPID::kMuon] = 0.;
2020 // Probabilities are not normalised yet
2022 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2028 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2031 Double_t probThreshold = -999.;
2033 // If there is only one distribution, the threshold corresponds to...
2037 else if (tofMode == 1) { // default
2038 probThreshold = 0.9973; // a 3-sigma inclusion cut
2040 else if (tofMode == 2) {
2045 Printf("ERROR: Bad TOF mode: %d!", tofMode);
2051 ///* OLD: cut with n-sigmas (ATTENTION: Does not take into account properly the TOF tail!)
2052 // Check kTOFout, kTIME, mismatch
2053 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->CheckPIDStatus(AliPIDResponse::kTOF, track);
2054 if (tofStatus != AliPIDResponse::kDetPidOk)
2057 Double_t nsigma[kNumTOFspecies + 1] = { -999., -999., -999., -999. };
2058 nsigma[kTOFpion] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kPion);
2059 nsigma[kTOFkaon] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kKaon);
2060 nsigma[kTOFproton] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton);
2062 Double_t inclusion = -999;
2063 Double_t exclusion = -999;
2069 else if (tofMode == 1) { // default
2073 else if (tofMode == 2) {
2078 Printf("ERROR: Bad TOF mode: %d!", tofMode);
2082 // Do not cut on nSigma electron because this would also remove pions in a large pT range.
2083 // The electron contamination of the pion sample can be treated by TPC dEdx fits afterwards.
2084 if (TMath::Abs(nsigma[kTOFpion]) < inclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
2086 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) < inclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
2088 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) < inclusion)
2092 // There are no TOF electrons selected because the purity is rather bad, even for small momenta
2093 // (also a small mismatch probability significantly affects electrons because their fraction
2094 // is small). There is no need for TOF electrons anyway, since the dEdx distribution of kaons and
2095 // protons in a given pT bin (also at the dEdx crossings) is very different from that of electrons.
2096 // This is due to the steeply falling dEdx of p and K with momentum, whereas the electron dEdx stays
2098 // As a result, the TPC fit yields a more accurate electron fraction than the TOF selection can do.
2104 // _________________________________________________________________________________
2105 Bool_t AliAnalysisTaskPID::IsSecondaryWithStrangeMotherMC(AliMCEvent* mcEvent, Int_t partLabel)
2107 // Check whether particle is a secondary with strange mother, i.e. returns kTRUE if a strange mother is found
2108 // and the particle is NOT a physical primary. In all other cases kFALSE is returned
2110 if (!mcEvent || partLabel < 0)
2113 AliMCParticle* part = (AliMCParticle*)mcEvent->GetTrack(partLabel);
2118 if (mcEvent->IsPhysicalPrimary(partLabel))
2121 Int_t iMother = part->GetMother();
2126 AliMCParticle* partM = (AliMCParticle*)mcEvent->GetTrack(iMother);
2130 Int_t codeM = TMath::Abs(partM->PdgCode());
2131 Int_t mfl = Int_t(codeM / TMath::Power(10, Int_t(TMath::Log10(codeM))));
2132 if (mfl == 3 && codeM != 3) // codeM = 3 is for s quark
2139 //_____________________________________________________________________________
2140 Bool_t AliAnalysisTaskPID::SetParticleFractionHisto(const TH3D* hist, Int_t species, Bool_t sysError)
2142 // Store a clone of hist (containing the particle fractions of the corresponding species with statistical error (sysError = kFALSE)
2143 // or systematic error (sysError = kTRUE), respectively), internally
2145 if (species < AliPID::kElectron || species > AliPID::kProton) {
2146 AliError(Form("Only fractions for species index %d to %d can be set, but not for the requested one: %d", 0,
2147 AliPID::kProton, species));
2152 delete fFractionSysErrorHists[species];
2154 fFractionSysErrorHists[species] = new TH3D(*hist);
2157 delete fFractionHists[species];
2159 fFractionHists[species] = new TH3D(*hist);
2166 //_____________________________________________________________________________
2167 Bool_t AliAnalysisTaskPID::SetParticleFractionHistosFromFile(const TString filePathName, Bool_t sysError)
2169 // Loads particle fractions for all species from the desired file and returns kTRUE on success.
2170 // The maps are assumed to be of Type TH3D, to sit in the main directory and to have names
2171 // Form("hFraction_%e", AliPID::ParticleName(i)) for sysError = kFALSE and
2172 // Form("hFractionSysError_%e", AliPID::ParticleName(i)) for sysError = kTRUE.
2174 TFile* f = TFile::Open(filePathName.Data());
2176 std::cout << "Failed to open file with particle fractions \"" << filePathName.Data() << "\"!" << std::endl;
2181 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
2182 TString histName = Form("hFraction%s_%s", sysError ? "SysError" : "", AliPID::ParticleName(i));
2183 hist = dynamic_cast<TH3D*>(f->Get(histName.Data()));
2185 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2186 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2187 CleanupParticleFractionHistos();
2191 if (!SetParticleFractionHisto(hist, i, sysError)) {
2192 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2193 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2194 CleanupParticleFractionHistos();
2206 //_____________________________________________________________________________
2207 Double_t AliAnalysisTaskPID::GetMaxEtaVariation(Double_t dEdxSplines)
2209 // Returns the maximum eta variation (i.e. deviation of eta correction factor from unity) for the
2210 // given (spline) dEdx
2212 if (dEdxSplines < 1. || !fhMaxEtaVariation) {
2213 Printf("Error GetMaxEtaVariation: No map or invalid dEdxSplines (%f)!", dEdxSplines);
2217 Int_t bin = fhMaxEtaVariation->GetXaxis()->FindFixBin(1. / dEdxSplines);
2221 if (bin > fhMaxEtaVariation->GetXaxis()->GetNbins())
2222 bin = fhMaxEtaVariation->GetXaxis()->GetNbins();
2224 return fhMaxEtaVariation->GetBinContent(bin);
2228 //_____________________________________________________________________________
2229 Int_t AliAnalysisTaskPID::GetRandomParticleTypeAccordingToParticleFractions(Double_t trackPt, Double_t jetPt,
2230 Double_t centralityPercentile,
2231 Bool_t smearByError,
2232 Bool_t takeIntoAccountSysError) const
2234 // Uses the stored histograms with the particle fractions to generate a random particle type according to these fractions.
2235 // In case of problems (e.g. histo missing), AliPID::kUnknown is returned.
2236 // If smearByError is kTRUE, the used fractions will be random numbers distributed with a gauss with mean
2237 // being the corresponding particle fraction and sigma it's error.
2238 // Note that in this case only the fraction of a random species is varied in this way. The other fractions
2239 // will be re-normalised according their statistical errors.
2240 // The same holds for the systematic error of species "takeIntoAccountSpeciesSysError", but the random number will be
2241 // uniformly distributed within [mean - sys, mean + sys] and the re-normalisation will be weighted with the systematic errors.
2242 // Note that the fractions will be calculated first with only the systematic error taken into account (if desired), including
2243 // re-normalisation. Then, the resulting fractions will be used to calculate the final fractions - either with statistical error
2244 // or without. The species, for which the error will be used for smearing, is the same for sys and stat error.
2246 Double_t prob[AliPID::kSPECIES];
2247 Int_t randomSpecies = (smearByError || takeIntoAccountSysError) ? (Int_t)(fRandom->Rndm() * AliPID::kSPECIES) : -1;
2248 Bool_t success = GetParticleFractions(trackPt, jetPt, centralityPercentile, prob, randomSpecies, randomSpecies);
2251 return AliPID::kUnknown;
2253 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2255 if (rnd <= prob[AliPID::kPion])
2256 return AliPID::kPion;
2257 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon])
2258 return AliPID::kKaon;
2259 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton])
2260 return AliPID::kProton;
2261 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton] + prob[AliPID::kElectron])
2262 return AliPID::kElectron;
2264 return AliPID::kMuon; //else it must be a muon (only species left)
2268 //_____________________________________________________________________________
2269 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::GenerateDetectorResponse(AliAnalysisTaskPID::ErrorCode errCode,
2270 Double_t mean, Double_t sigma,
2271 Double_t* responses, Int_t nResponses,
2274 // Generate detector response. If a previous generation was not successful or there is something wrong with this signal generation,
2275 // the function will return kFALSE
2279 // Reset response array
2280 for (Int_t i = 0; i < nResponses; i++)
2281 responses[i] = -999;
2283 if (errCode == kError)
2286 ErrorCode ownErrCode = kNoErrors;
2288 if (fUseConvolutedGaus && !usePureGaus) {
2289 // In case of convoluted gauss, calculate the probability density only once to save a lot of time!
2291 TH1* hProbDensity = 0x0;
2292 ownErrCode = SetParamsForConvolutedGaus(mean, sigma);
2293 if (ownErrCode == kError)
2296 hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
2298 for (Int_t i = 0; i < nResponses; i++) {
2299 responses[i] = hProbDensity->GetRandom();
2300 //responses[i] fConvolutedGausDeltaPrime->GetRandom(); // MUCH slower than using the binned version via the histogram
2304 for (Int_t i = 0; i < nResponses; i++) {
2305 responses[i] = fRandom->Gaus(mean, sigma);
2309 // If forwarded error code was a warning (error case has been handled before), return a warning
2310 if (errCode == kWarning)
2313 return ownErrCode; // Forward success/warning
2317 //_____________________________________________________________________________
2318 void AliAnalysisTaskPID::PrintSettings(Bool_t printSystematicsSettings) const
2320 // Print current settings.
2322 printf("\n\nSettings for task %s:\n", GetName());
2323 printf("Is pPb/Pbp: %d -> %s\n", GetIsPbpOrpPb(), GetIsPbpOrpPb() ? "Adapting vertex cuts" : "Using standard vertex cuts");
2324 printf("Track cuts: %s\n", fTrackFilter ? fTrackFilter->GetTitle() : "-");
2325 printf("Eta cut: %.2f <= |eta| <= %.2f\n", GetEtaAbsCutLow(), GetEtaAbsCutUp());
2326 printf("Phi' cut: %d\n", GetUsePhiCut());
2327 printf("TPCCutMIGeo: %d\n", GetUseTPCCutMIGeo());
2328 if (GetUseTPCCutMIGeo()) {
2329 printf("GetCutGeo: %f\n", GetCutGeo());
2330 printf("GetCutNcr: %f\n", GetCutNcr());
2331 printf("GetCutNcl: %f\n", GetCutNcl());
2333 printf("TPCnclCut: %d\n", GetUseTPCnclCut());
2334 if (GetUseTPCnclCut()) {
2335 printf("GetCutPureNcl: %d\n", GetCutPureNcl());
2340 printf("Centrality estimator: %s\n", GetCentralityEstimator().Data());
2344 printf("Pile up rejection type: %d\n", (Int_t)fPileUpRejectionType);
2348 printf("Use MC-ID for signal generation: %d\n", GetUseMCidForGeneration());
2349 printf("Use ITS: %d\n", GetUseITS());
2350 printf("Use TOF: %d\n", GetUseTOF());
2351 printf("Use priors: %d\n", GetUsePriors());
2352 printf("Use TPC default priors: %d\n", GetUseTPCDefaultPriors());
2353 printf("Use convoluted Gauss: %d\n", GetUseConvolutedGaus());
2354 printf("Accuracy of non-Gaussian tail: %e\n", GetAccuracyNonGaussianTail());
2355 printf("Take into account muons: %d\n", GetTakeIntoAccountMuons());
2356 printf("TOF mode: %d\n", GetTOFmode());
2357 printf("\nParams for transition from gauss to asymmetric shape:\n");
2358 printf("[0]: %e\n", GetConvolutedGaussTransitionPar(0));
2359 printf("[1]: %e\n", GetConvolutedGaussTransitionPar(1));
2360 printf("[2]: %e\n", GetConvolutedGaussTransitionPar(2));
2364 printf("Do PID: %d\n", fDoPID);
2365 printf("Do Efficiency: %d\n", fDoEfficiency);
2366 printf("Do PtResolution: %d\n", fDoPtResolution);
2367 printf("Do dEdxCheck: %d\n", fDoDeDxCheck);
2368 printf("Do binZeroStudy: %d\n", fDoBinZeroStudy);
2372 printf("Input from other task: %d\n", GetInputFromOtherTask());
2373 printf("Store additional jet information: %d\n", GetStoreAdditionalJetInformation());
2374 printf("Store centrality percentile: %d", GetStoreCentralityPercentile());
2376 if (printSystematicsSettings)
2377 PrintSystematicsSettings();
2383 //_____________________________________________________________________________
2384 void AliAnalysisTaskPID::PrintSystematicsSettings() const
2386 // Print current settings for systematic studies.
2388 printf("\n\nSettings for systematics for task %s:\n", GetName());
2389 printf("SplinesThr:\t%f\n", GetSystematicScalingSplinesThreshold());
2390 printf("SplinesBelowThr:\t%f\n", GetSystematicScalingSplinesBelowThreshold());
2391 printf("SplinesAboveThr:\t%f\n", GetSystematicScalingSplinesAboveThreshold());
2392 printf("EtaCorrMomThr:\t%f\n", GetSystematicScalingEtaCorrectionMomentumThr());
2393 printf("EtaCorrLowP:\t%f\n", GetSystematicScalingEtaCorrectionLowMomenta());
2394 printf("EtaCorrHighP:\t%f\n", GetSystematicScalingEtaCorrectionHighMomenta());
2395 printf("SigmaParaThr:\t%f\n", GetSystematicScalingEtaSigmaParaThreshold());
2396 printf("SigmaParaBelowThr:\t%f\n", GetSystematicScalingEtaSigmaParaBelowThreshold());
2397 printf("SigmaParaAboveThr:\t%f\n", GetSystematicScalingEtaSigmaParaAboveThreshold());
2398 printf("MultCorr:\t%f\n", GetSystematicScalingMultCorrection());
2399 printf("TOF mode: %d\n", GetTOFmode());
2405 //_____________________________________________________________________________
2406 Bool_t AliAnalysisTaskPID::ProcessTrack(const AliVTrack* track, Int_t particlePDGcode, Double_t centralityPercentile,
2409 // Process the track (generate expected response, fill histos, etc.).
2410 // particlePDGcode == 0 means data. Otherwise, the corresponding MC ID will be assumed.
2412 //Printf("Debug: Task %s is starting to process track: dEdx %f, pTPC %f, eta %f, ncl %d\n", GetName(), track->GetTPCsignal(), track->GetTPCmomentum(),
2413 // track->Eta(), track->GetTPCsignalN());
2416 printf("File: %s, Line: %d: ProcessTrack\n", (char*)__FILE__, __LINE__);
2418 if (!fDoPID && !fDoDeDxCheck && !fDoPtResolution)
2422 printf("File: %s, Line: %d: ProcessTrack -> Processing started\n", (char*)__FILE__, __LINE__);
2424 const Bool_t isMC = (particlePDGcode == 0) ? kFALSE : kTRUE;
2429 if (TMath::Abs(particlePDGcode) == 211) {//Pion
2432 else if (TMath::Abs(particlePDGcode) == 321) {//Kaon
2435 else if (TMath::Abs(particlePDGcode) == 2212) {//Proton
2438 else if (TMath::Abs(particlePDGcode) == 11) {//Electron
2441 else if (TMath::Abs(particlePDGcode) == 13) {//Muon
2444 else // In MC-ID case, set to underflow bin such that the response from this track is only used for unidentified signal generation
2445 // or signal generation with PID response and the track is still there (as in data) - e.g. relevant w.r.t. deuterons.
2446 // This is important to be as much as possible consistent with data. And the tracks can still be removed by disabling the
2447 // underflow bin for the projections
2452 //Double_t p = track->GetP();
2453 const Double_t pTPC = track->GetTPCmomentum();
2454 Double_t pT = track->Pt();
2456 Double_t z = -1, xi = -1;
2457 GetJetTrackObservables(pT, jetPt, z, xi);
2460 Double_t trackCharge = track->Charge();
2463 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
2464 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
2465 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
2469 Printf("Skipping track with strange dEdx value: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), pTPC,
2470 track->Eta(), track->GetTPCsignalN());
2474 // Completely remove tracks from light nuclei defined by el and pr <dEdx> as function of pT.
2475 // A very loose cut to be sure not to throw away electrons and/or protons
2476 Double_t nSigmaPr = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kProton);
2477 Double_t nSigmaEl = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kElectron);
2479 if ((pTPC >= 0.3 && (nSigmaPr > 10 && nSigmaEl > 10)) ||
2480 (pTPC < 0.3 && (nSigmaPr > 15 && nSigmaEl > 15))) {
2482 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",
2483 track->GetTPCsignal(), pTPC, pT, track->Eta(), track->GetTPCsignalN(), nSigmaPr, nSigmaEl);
2488 Double_t dEdxEl, dEdxKa, dEdxPi, dEdxMu, dEdxPr;
2489 Double_t sigmaEl, sigmaKa, sigmaPi, sigmaMu, sigmaPr;
2491 if (fDoAnySystematicStudiesOnTheExpectedSignal) {
2492 // Get the uncorrected signal first and the corresponding correction factors.
2493 // Then modify the correction factors and properly recalculate the corrected dEdx
2495 // Get pure spline values for dEdx_expected, without any correction
2496 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2497 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2498 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2499 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2500 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2501 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2503 // Scale splines, if desired
2504 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
2505 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
2507 // Tune turn-on of correction for pions (not so relevant for the other species, since at very large momenta)
2509 Double_t scaleFactor = 1.;
2510 Double_t usedSystematicScalingSplines = 1.;
2512 bg = pTPC / AliPID::ParticleMass(AliPID::kElectron);
2513 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2514 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2515 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2516 dEdxEl *= usedSystematicScalingSplines;
2518 bg = pTPC / AliPID::ParticleMass(AliPID::kKaon);
2519 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2520 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2521 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2522 dEdxKa *= usedSystematicScalingSplines;
2524 bg = pTPC / AliPID::ParticleMass(AliPID::kPion);
2525 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2526 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2527 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2528 dEdxPi *= usedSystematicScalingSplines;
2530 if (fTakeIntoAccountMuons) {
2531 bg = pTPC / AliPID::ParticleMass(AliPID::kMuon);
2532 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2533 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2534 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2535 dEdxMu *= usedSystematicScalingSplines;
2539 bg = pTPC / AliPID::ParticleMass(AliPID::kProton);
2540 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2541 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2542 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2543 dEdxPr *= usedSystematicScalingSplines;
2546 // Get the eta correction factors for the (modified) expected dEdx
2547 Double_t etaCorrEl = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxEl) : 1.;
2548 Double_t etaCorrKa = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxKa) : 1.;
2549 Double_t etaCorrPi = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPi) : 1.;
2550 Double_t etaCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCEtaCorrection() ?
2551 fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxMu) : 1.;
2552 Double_t etaCorrPr = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPr) : 1.;
2554 // Scale eta correction factors, if desired (and eta correction maps are to be used, otherwise it is not possible!)
2555 if (fPIDResponse->UseTPCEtaCorrection() &&
2556 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon ||
2557 TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon)) {
2558 // Since we do not want to scale the splines with this, but only the eta variation, only scale the deviation of the correction factor!
2559 // 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!
2562 // Due to additional azimuthal effects, there is an additional eta dependence for low momenta which is not corrected successfully so far.
2563 // One can assign a different (higher) systematic scale factor for this low-p region and a threshold which separates low- and high-p.
2564 // 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
2565 Double_t usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionHighMomenta;
2567 if (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - fSystematicScalingEtaCorrectionLowMomenta) > fgkEpsilon) {
2568 const Double_t fractionHighMomentumScaleFactor = 0.5 * (1. + TMath::Erf((pTPC - fSystematicScalingEtaCorrectionMomentumThr) / 0.1));
2569 usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionLowMomenta * (1 - fractionHighMomentumScaleFactor)
2570 + fSystematicScalingEtaCorrectionHighMomenta * fractionHighMomentumScaleFactor;
2573 Double_t maxEtaVariationEl = GetMaxEtaVariation(dEdxEl);
2574 etaCorrEl = etaCorrEl * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrEl - 1.0) / maxEtaVariationEl);
2576 Double_t maxEtaVariationKa = GetMaxEtaVariation(dEdxKa);
2577 etaCorrKa = etaCorrKa * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrKa - 1.0) / maxEtaVariationKa);
2579 Double_t maxEtaVariationPi = GetMaxEtaVariation(dEdxPi);
2580 etaCorrPi = etaCorrPi * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPi - 1.0) / maxEtaVariationPi);
2582 if (fTakeIntoAccountMuons) {
2583 Double_t maxEtaVariationMu = GetMaxEtaVariation(dEdxMu);
2584 etaCorrMu = etaCorrMu * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrMu - 1.0) / maxEtaVariationMu);
2589 Double_t maxEtaVariationPr = GetMaxEtaVariation(dEdxPr);
2590 etaCorrPr = etaCorrPr * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPr - 1.0) / maxEtaVariationPr);
2594 etaCorrEl = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrEl - 1.0);
2595 etaCorrKa = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrKa - 1.0);
2596 etaCorrPi = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPi - 1.0);
2597 etaCorrMu = fTakeIntoAccountMuons ? (1.0 + usedSystematicScalingEtaCorrection * (etaCorrMu - 1.0)) : 1.0;
2598 etaCorrPr = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPr - 1.0);
2602 // Get the multiplicity correction factors for the (modified) expected dEdx
2603 const Int_t currEvtMultiplicity = fPIDResponse->GetTPCResponse().GetCurrentEventMultiplicity();
2605 Double_t multiplicityCorrEl = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2606 dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2607 Double_t multiplicityCorrKa = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2608 dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2609 Double_t multiplicityCorrPi = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2610 dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2611 Double_t multiplicityCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2612 fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track, dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2613 Double_t multiplicityCorrPr = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2614 dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2616 Double_t multiplicityCorrSigmaEl = fPIDResponse->UseTPCMultiplicityCorrection() ?
2617 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2618 Double_t multiplicityCorrSigmaKa = fPIDResponse->UseTPCMultiplicityCorrection() ?
2619 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2620 Double_t multiplicityCorrSigmaPi = fPIDResponse->UseTPCMultiplicityCorrection() ?
2621 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2622 Double_t multiplicityCorrSigmaMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2623 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2624 Double_t multiplicityCorrSigmaPr = fPIDResponse->UseTPCMultiplicityCorrection() ?
2625 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2627 // Scale multiplicity correction factors, if desired (and multiplicity correction functions are to be used, otherwise it is not possible!)
2628 if (fPIDResponse->UseTPCMultiplicityCorrection() && TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
2629 // Since we do not want to scale the splines with this, but only the multiplicity variation, only scale the deviation of the correction factor!
2630 // 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!
2632 multiplicityCorrEl = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrEl - 1.0);
2633 multiplicityCorrKa = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrKa - 1.0);
2634 multiplicityCorrPi = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPi - 1.0);
2635 multiplicityCorrMu = fTakeIntoAccountMuons ? (1.0 + fSystematicScalingMultCorrection * (multiplicityCorrMu - 1.0)) : 1.0;
2636 multiplicityCorrPr = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPr - 1.0);
2639 // eta correction must be enabled in order to use the new sigma parametrisation maps. Since this is the absolute sigma
2640 // for a track calculated with the unscaled paramaters, we have to devide out dEdxExpectedEtaCorrected and then need
2641 // to scale with the multiplicitySigmaCorrFactor * fSystematicScalingEtaSigmaPara. In the end, one has to scale with the
2642 // (modified) dEdx to get the absolute sigma
2643 // This means there is no extra parameter for the multiplicitySigmaCorrFactor, but only for the sigma map itself.
2644 // This is valid, since it appears only as a product. One has to assume a larger systematic shift in case of additional
2645 // multiplicity dependence....
2647 Bool_t doSigmaSystematics = (TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
2648 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon);
2651 Double_t dEdxElExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2653 Double_t systematicScalingEtaSigmaParaEl = 1.;
2654 if (doSigmaSystematics) {
2655 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxElExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2656 systematicScalingEtaSigmaParaEl = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2657 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2659 Double_t sigmaRelEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2661 / dEdxElExpected * systematicScalingEtaSigmaParaEl * multiplicityCorrSigmaEl;
2664 Double_t dEdxKaExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2666 Double_t systematicScalingEtaSigmaParaKa = 1.;
2667 if (doSigmaSystematics) {
2668 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxKaExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2669 systematicScalingEtaSigmaParaKa = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2670 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2672 Double_t sigmaRelKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2674 / dEdxKaExpected * systematicScalingEtaSigmaParaKa * multiplicityCorrSigmaKa;
2677 Double_t dEdxPiExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2679 Double_t systematicScalingEtaSigmaParaPi = 1.;
2680 if (doSigmaSystematics) {
2681 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPiExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2682 systematicScalingEtaSigmaParaPi = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2683 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2685 Double_t sigmaRelPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2687 / dEdxPiExpected * systematicScalingEtaSigmaParaPi * multiplicityCorrSigmaPi;
2690 Double_t sigmaRelMu = 999.;
2691 if (fTakeIntoAccountMuons) {
2692 Double_t dEdxMuExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2694 Double_t systematicScalingEtaSigmaParaMu = 1.;
2695 if (doSigmaSystematics) {
2696 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxMuExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2697 systematicScalingEtaSigmaParaMu = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2698 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2700 sigmaRelMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kTRUE, kFALSE)
2701 / dEdxMuExpected * systematicScalingEtaSigmaParaMu * multiplicityCorrSigmaMu;
2705 Double_t dEdxPrExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2707 Double_t systematicScalingEtaSigmaParaPr = 1.;
2708 if (doSigmaSystematics) {
2709 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPrExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2710 systematicScalingEtaSigmaParaPr = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2711 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2713 Double_t sigmaRelPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2715 / dEdxPrExpected * systematicScalingEtaSigmaParaPr * multiplicityCorrSigmaPr;
2717 // Now scale the (possibly modified) spline values with the (possibly modified) correction factors
2718 dEdxEl *= etaCorrEl * multiplicityCorrEl;
2719 dEdxKa *= etaCorrKa * multiplicityCorrKa;
2720 dEdxPi *= etaCorrPi * multiplicityCorrPi;
2721 dEdxMu *= etaCorrMu * multiplicityCorrMu;
2722 dEdxPr *= etaCorrPr * multiplicityCorrPr;
2724 // Finally, get the absolute sigma
2725 sigmaEl = sigmaRelEl * dEdxEl;
2726 sigmaKa = sigmaRelKa * dEdxKa;
2727 sigmaPi = sigmaRelPi * dEdxPi;
2728 sigmaMu = sigmaRelMu * dEdxMu;
2729 sigmaPr = sigmaRelPr * dEdxPr;
2733 // No systematic studies on expected signal - just take it as it comes from the TPCPIDResponse
2734 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2735 fPIDResponse->UseTPCEtaCorrection(),
2736 fPIDResponse->UseTPCMultiplicityCorrection());
2737 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2738 fPIDResponse->UseTPCEtaCorrection(),
2739 fPIDResponse->UseTPCMultiplicityCorrection());
2740 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2741 fPIDResponse->UseTPCEtaCorrection(),
2742 fPIDResponse->UseTPCMultiplicityCorrection());
2743 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2744 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2745 fPIDResponse->UseTPCEtaCorrection(),
2746 fPIDResponse->UseTPCMultiplicityCorrection());
2747 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2748 fPIDResponse->UseTPCEtaCorrection(),
2749 fPIDResponse->UseTPCMultiplicityCorrection());
2751 sigmaEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2752 fPIDResponse->UseTPCEtaCorrection(),
2753 fPIDResponse->UseTPCMultiplicityCorrection());
2754 sigmaKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2755 fPIDResponse->UseTPCEtaCorrection(),
2756 fPIDResponse->UseTPCMultiplicityCorrection());
2757 sigmaPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2758 fPIDResponse->UseTPCEtaCorrection(),
2759 fPIDResponse->UseTPCMultiplicityCorrection());
2760 sigmaMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2761 fPIDResponse->UseTPCEtaCorrection(),
2762 fPIDResponse->UseTPCMultiplicityCorrection());
2763 sigmaPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2764 fPIDResponse->UseTPCEtaCorrection(),
2765 fPIDResponse->UseTPCMultiplicityCorrection());
2768 Double_t deltaPrimeElectron = (dEdxEl > 0) ? dEdxTPC / dEdxEl : -1;
2770 Printf("Error: Expected TPC signal <= 0 for electron hypothesis");
2774 Double_t deltaPrimeKaon = (dEdxKa > 0) ? dEdxTPC / dEdxKa : -1;
2776 Printf("Error: Expected TPC signal <= 0 for kaon hypothesis");
2780 Double_t deltaPrimePion = (dEdxPi > 0) ? dEdxTPC / dEdxPi : -1;
2782 Printf("Error: Expected TPC signal <= 0 for pion hypothesis");
2786 Double_t deltaPrimeProton = (dEdxPr > 0) ? dEdxTPC / dEdxPr : -1;
2788 Printf("Error: Expected TPC signal <= 0 for proton hypothesis");
2793 printf("File: %s, Line: %d: ProcessTrack -> Compute probabilities\n", (char*)__FILE__, __LINE__);
2796 // Use probabilities to weigh the response generation for the different species.
2797 // Also determine the most probable particle type.
2798 Double_t prob[AliPID::kSPECIESC];
2799 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2802 fPIDcombined->ComputeProbabilities(track, fPIDResponse, prob);
2804 // If muons are not to be taken into account, just set their probability to zero and normalise the remaining probabilities later
2805 if (!fTakeIntoAccountMuons)
2806 prob[AliPID::kMuon] = 0;
2808 // Priors might cause problems in case of mismatches, i.e. mismatch particles will be identified as pions.
2809 // Can be easily caught for low p_TPC by just setting pion (and muon) probs to zero, if dEdx is larger than
2810 // expected dEdx of electrons and kaons
2811 if (pTPC < 1. && dEdxTPC > dEdxEl && dEdxTPC > dEdxKa) {
2812 prob[AliPID::kMuon] = 0;
2813 prob[AliPID::kPion] = 0;
2817 // Bug: One can set the number of species for PIDcombined, but PIDcombined will call PIDresponse, which writes without testing
2818 // the probs for kSPECIESC (including light nuclei) into the array.
2819 // In this case, when only kSPECIES are considered, the probabilities have to be rescaled!
2822 // 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
2823 // high-pT region (also contribution there completely negligable!)
2824 // 2. If dEdx is larger than the expected dEdx + 5 sigma of el and pr, it is most likely a light nucleus
2825 // (if dEdx is more than 5 sigma away from expectation, flat TPC probs are set... and the light nuclei splines are not
2828 // The highest expected dEdx is either for pr or for el. Assign 100% probability to the species with highest expected dEdx then.
2829 // In all other cases: Throw away light nuclei probs and rescale other probs to 100%.
2831 // Find most probable species for the ID
2832 Int_t maxIndex = TMath::LocMax(AliPID::kSPECIESC, prob);
2834 if ((prob[maxIndex] > 0 && maxIndex >= AliPID::kSPECIES && dEdxTPC > dEdxEl + 5. * sigmaEl) ||
2835 (dEdxTPC > dEdxEl + 5. * sigmaEl && dEdxTPC > dEdxPr + 5. * sigmaPr)) {
2836 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2839 if (dEdxEl > dEdxPr) {
2840 prob[AliPID::kElectron] = 1.;
2841 maxIndex = AliPID::kElectron;
2844 prob[AliPID::kProton] = 1.;
2845 maxIndex = AliPID::kProton;
2849 for (Int_t i = AliPID::kSPECIES; i < AliPID::kSPECIESC; i++)
2852 Double_t probSum = 0.;
2853 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2857 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2861 // If all probabilities are equal (should only happen if no priors are used), set most probable PID to pion
2862 // because LocMax returns just the first maximal value (i.e. AliPID::kElectron)
2863 if (TMath::Abs(prob[maxIndex] - 1. / AliPID::kSPECIES) < 1e-5)
2864 maxIndex = AliPID::kPion;
2866 // In all other cases, the maximum remains untouched from the scaling (and is < AliPID::kSPECIES by construction)
2870 // Generate the expected responses in DeltaPrime and translate to real dEdx. Only take responses for exactly that species
2871 // (i.e. with pre-PID)
2873 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
2875 ErrorCode errCode = kNoErrors;
2878 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check\n", (char*)__FILE__, __LINE__);
2881 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
2884 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
2887 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
2890 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
2892 if (errCode == kNoErrors) {
2893 Double_t genEntry[kDeDxCheckNumAxes];
2894 genEntry[kDeDxCheckJetPt] = jetPt;
2895 genEntry[kDeDxCheckEtaAbs] = TMath::Abs(track->Eta());
2896 genEntry[kDeDxCheckP] = pTPC;
2899 for (Int_t n = 0; n < numGenEntries; n++) {
2900 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
2901 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2903 // Consider generated response as originating from...
2904 if (rnd <= prob[AliPID::kElectron]) {
2905 genEntry[kDeDxCheckPID] = 0; // ... an electron
2906 genEntry[kDeDxCheckDeDx] = fGenRespElDeltaPrimeEl[n] * dEdxEl;
2908 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon]) {
2909 genEntry[kDeDxCheckPID] = 1; // ... a kaon
2910 genEntry[kDeDxCheckDeDx] = fGenRespKaDeltaPrimeKa[n] * dEdxKa;
2912 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion]) {
2913 genEntry[kDeDxCheckPID] = 2; // ... a pion (or a muon)
2914 genEntry[kDeDxCheckDeDx] = fGenRespPiDeltaPrimePi[n] * dEdxPi;
2917 genEntry[kDeDxCheckPID] = 3; // ... a proton
2918 genEntry[kDeDxCheckDeDx] = fGenRespPrDeltaPrimePr[n] * dEdxPr;
2921 fDeDxCheck->Fill(genEntry);
2926 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check done\n", (char*)__FILE__, __LINE__);
2929 if (fDoPtResolution) {
2930 // Check shared clusters, which is done together with the pT resolution
2931 Double_t qaEntry[kQASharedClsNumAxes];
2932 qaEntry[kQASharedClsJetPt] = jetPt;
2933 qaEntry[kQASharedClsPt] = pT;
2934 qaEntry[kDeDxCheckP] = pTPC;
2935 qaEntry[kQASharedClsNumSharedCls] = track->GetTPCSharedMapPtr()->CountBits();
2938 // iRowInd == -1 for "all rows w/o multiple counting"
2939 qaEntry[kQASharedClsPadRow] = iRowInd;
2940 fQASharedCls->Fill(qaEntry);
2942 // Fill hist for every pad row with shared cluster
2943 for (iRowInd = 0; iRowInd < 159; iRowInd++) {
2944 if (track->GetTPCSharedMapPtr()->TestBitNumber(iRowInd)) {
2945 qaEntry[kQASharedClsPadRow] = iRowInd;
2946 fQASharedCls->Fill(qaEntry);
2955 // Clean up the most probable PID for low momenta (not an issue for the probabilities, since fractions small,
2956 // but to get clean (and nice looking) templates (if most probable PID is used instead of generated responses), it should be done).
2957 // Problem: If more than 5 sigma away (and since priors also included), most probable PID for dEdx around protons could be pions.
2958 // Idea: Only clean selection for K and p possible. So, just take for the most probable PID the probs from TPC only calculated
2959 // by hand without restriction to 5 sigma and without priors. This will not affect the template generation, but afterwards one
2960 // can replace the K and p templates with the most probable PID distributions, so all other species templates remain the same.
2961 // I.e. it doesn't hurt if the most probable PID is distributed incorrectly between el, pi, mu.
2962 Bool_t maxIndexSetManually = kFALSE;
2965 Double_t probManualTPC[AliPID::kSPECIES];
2966 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2967 probManualTPC[i] = 0;
2969 probManualTPC[AliPID::kElectron] = TMath::Exp(-0.5*(dEdxTPC-dEdxEl)*(dEdxTPC-dEdxEl)/(sigmaEl*sigmaEl))/sigmaEl;
2970 // Muons are not important here, just ignore and save processing time
2971 probManualTPC[AliPID::kMuon] = 0.;//TMath::Exp(-0.5*(dEdxTPC-dEdxMu)*(dEdxTPC-dEdxMu)/(sigmaMu*sigmaMu))/sigmaMu;
2972 probManualTPC[AliPID::kPion] = TMath::Exp(-0.5*(dEdxTPC-dEdxPi)*(dEdxTPC-dEdxPi)/(sigmaPi*sigmaPi))/sigmaPi;
2973 probManualTPC[AliPID::kKaon] = TMath::Exp(-0.5*(dEdxTPC-dEdxKa)*(dEdxTPC-dEdxKa)/(sigmaKa*sigmaKa))/sigmaKa;
2974 probManualTPC[AliPID::kProton] = TMath::Exp(-0.5*(dEdxTPC-dEdxPr)*(dEdxTPC-dEdxPr)/(sigmaPr*sigmaPr))/sigmaPr;
2976 const Int_t maxIndexManualTPC = TMath::LocMax(AliPID::kSPECIES, probManualTPC);
2977 // Should always be > 0, but in case the dEdx is far off such that the machine accuracy sets every prob to zero,
2978 // better take the "old" result
2979 if (probManualTPC[maxIndexManualTPC] > 0.)
2980 maxIndex = maxIndexManualTPC;
2982 maxIndexSetManually = kTRUE;
2986 // Translate from AliPID numbering to numbering of this class
2987 if (prob[maxIndex] > 0 || maxIndexSetManually) {
2988 if (maxIndex == AliPID::kElectron)
2990 else if (maxIndex == AliPID::kKaon)
2992 else if (maxIndex == AliPID::kMuon)
2994 else if (maxIndex == AliPID::kPion)
2996 else if (maxIndex == AliPID::kProton)
3002 // Only take track into account for expectation values, if valid pid response is available.. Otherwise: Set to underflow bin.
3008 //For testing: Swap p<->pT to analyse pure p-dependence => Needs to be removed later
3014 TOFpidInfo tofPIDinfo = GetTOFType(track, fTOFmode);
3016 Double_t entry[fStoreAdditionalJetInformation ? kDataNumAxes : kDataNumAxes - fgkNumJetAxes];
3017 entry[kDataMCID] = binMC;
3018 entry[kDataSelectSpecies] = 0;
3019 entry[kDataPt] = pT;
3020 entry[kDataDeltaPrimeSpecies] = deltaPrimeElectron;
3021 entry[kDataCentrality] = centralityPercentile;
3023 if (fStoreAdditionalJetInformation) {
3024 entry[kDataJetPt] = jetPt;
3026 entry[kDataXi] = xi;
3029 entry[GetIndexOfChargeAxisData()] = trackCharge;
3030 entry[GetIndexOfTOFpidInfoAxisData()] = tofPIDinfo;
3032 fhPIDdataAll->Fill(entry);
3034 entry[kDataSelectSpecies] = 1;
3035 entry[kDataDeltaPrimeSpecies] = deltaPrimeKaon;
3036 fhPIDdataAll->Fill(entry);
3038 entry[kDataSelectSpecies] = 2;
3039 entry[kDataDeltaPrimeSpecies] = deltaPrimePion;
3040 fhPIDdataAll->Fill(entry);
3042 entry[kDataSelectSpecies] = 3;
3043 entry[kDataDeltaPrimeSpecies] = deltaPrimeProton;
3044 fhPIDdataAll->Fill(entry);
3047 // Construct the expected shape for the transition p -> pT
3049 Double_t genEntry[fStoreAdditionalJetInformation ? kGenNumAxes : kGenNumAxes - fgkNumJetAxes];
3050 genEntry[kGenMCID] = binMC;
3051 genEntry[kGenSelectSpecies] = 0;
3052 genEntry[kGenPt] = pT;
3053 genEntry[kGenDeltaPrimeSpecies] = -999;
3054 genEntry[kGenCentrality] = centralityPercentile;
3056 if (fStoreAdditionalJetInformation) {
3057 genEntry[kGenJetPt] = jetPt;
3058 genEntry[kGenZ] = z;
3059 genEntry[kGenXi] = xi;
3062 genEntry[GetIndexOfChargeAxisGen()] = trackCharge;
3063 genEntry[GetIndexOfTOFpidInfoAxisGen()] = tofPIDinfo;
3065 // Generate numGenEntries "responses" with fluctuations around the expected values.
3066 // fgkMaxNumGenEntries = 500 turned out to give reasonable templates even for highest track pT in 15-20 GeV/c jet pT bin.
3067 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
3069 /*OLD: Different number of responses depending on pT and jet pT for fgkMaxNumGenEntries = 1000
3070 * => Problem: If threshold to higher number of responses inside a bin (or after rebinning), then the template
3071 * is biased to the higher pT.
3072 // Generate numGenEntries "responses" with fluctuations around the expected values.
3073 // The higher the (transverse) momentum, the more "responses" will be generated in order not to run out of statistics too fast.
3074 Int_t numGenEntries = 10;
3076 // Jets have even worse statistics, therefore, scale numGenEntries further
3078 numGenEntries *= 20;
3079 else if (jetPt >= 20)
3080 numGenEntries *= 10;
3081 else if (jetPt >= 10)
3086 // Do not generate more entries than available in memory!
3087 if (numGenEntries > fgkMaxNumGenEntries)// fgkMaxNumGenEntries = 1000
3088 numGenEntries = fgkMaxNumGenEntries;
3092 ErrorCode errCode = kNoErrors;
3095 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses\n", (char*)__FILE__, __LINE__);
3098 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
3099 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxKa, sigmaEl / dEdxKa, fGenRespElDeltaPrimeKa, numGenEntries);
3100 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPi, sigmaEl / dEdxPi, fGenRespElDeltaPrimePi, numGenEntries);
3101 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPr, sigmaEl / dEdxPr, fGenRespElDeltaPrimePr, numGenEntries);
3104 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxEl, sigmaKa / dEdxEl, fGenRespKaDeltaPrimeEl, numGenEntries);
3105 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
3106 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPi, sigmaKa / dEdxPi, fGenRespKaDeltaPrimePi, numGenEntries);
3107 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPr, sigmaKa / dEdxPr, fGenRespKaDeltaPrimePr, numGenEntries);
3110 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxEl, sigmaPi / dEdxEl, fGenRespPiDeltaPrimeEl, numGenEntries);
3111 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxKa, sigmaPi / dEdxKa, fGenRespPiDeltaPrimeKa, numGenEntries);
3112 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
3113 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxPr, sigmaPi / dEdxPr, fGenRespPiDeltaPrimePr, numGenEntries);
3115 // Muons, if desired
3116 if (fTakeIntoAccountMuons) {
3117 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxEl, sigmaMu / dEdxEl, fGenRespMuDeltaPrimeEl, numGenEntries);
3118 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxKa, sigmaMu / dEdxKa, fGenRespMuDeltaPrimeKa, numGenEntries);
3119 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPi, sigmaMu / dEdxPi, fGenRespMuDeltaPrimePi, numGenEntries);
3120 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPr, sigmaMu / dEdxPr, fGenRespMuDeltaPrimePr, numGenEntries);
3124 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxEl, sigmaPr / dEdxEl, fGenRespPrDeltaPrimeEl, numGenEntries);
3125 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxKa, sigmaPr / dEdxKa, fGenRespPrDeltaPrimeKa, numGenEntries);
3126 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxPi, sigmaPr / dEdxPi, fGenRespPrDeltaPrimePi, numGenEntries);
3127 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
3129 if (errCode != kNoErrors) {
3130 if (errCode == kWarning && fDebug > 1) {
3131 Printf("Warning: Questionable detector response for track, most likely due to very low number of PID clusters! Debug output (dEdx_expected, sigma_expected):");
3134 Printf("Error: Failed to generate detector response for track - skipped! Debug output (dEdx_expected, sigma_expected):");
3137 Printf("Pr: %e, %e", dEdxPr, sigmaPr);
3138 Printf("Pi: %e, %e", dEdxPi, sigmaPi);
3139 Printf("El: %e, %e", dEdxEl, sigmaEl);
3140 Printf("Mu: %e, %e", dEdxMu, sigmaMu);
3141 Printf("Ka: %e, %e", dEdxKa, sigmaKa);
3142 Printf("track: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), track->GetTPCmomentum(), track->Eta(),
3143 track->GetTPCsignalN());
3146 if (errCode != kWarning) {
3147 return kFALSE;// Skip generated response in case of error
3151 for (Int_t n = 0; n < numGenEntries; n++) {
3152 if (!isMC || !fUseMCidForGeneration) {
3153 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
3154 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
3156 // Consider generated response as originating from...
3157 if (rnd <= prob[AliPID::kElectron])
3158 genEntry[kGenMCID] = 0; // ... an electron
3159 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon])
3160 genEntry[kGenMCID] = 1; // ... a kaon
3161 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon])
3162 genEntry[kGenMCID] = 2; // ... a muon -> NOTE: prob[AliPID::kMuon] = 0 in case of fTakeIntoAccountMuons = kFALSE
3163 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion])
3164 genEntry[kGenMCID] = 3; // ... a pion
3166 genEntry[kGenMCID] = 4; // ... a proton
3170 genEntry[kGenSelectSpecies] = 0;
3171 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeEl[n];
3172 fhGenEl->Fill(genEntry);
3174 genEntry[kGenSelectSpecies] = 1;
3175 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeKa[n];
3176 fhGenEl->Fill(genEntry);
3178 genEntry[kGenSelectSpecies] = 2;
3179 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePi[n];
3180 fhGenEl->Fill(genEntry);
3182 genEntry[kGenSelectSpecies] = 3;
3183 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePr[n];
3184 fhGenEl->Fill(genEntry);
3187 genEntry[kGenSelectSpecies] = 0;
3188 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeEl[n];
3189 fhGenKa->Fill(genEntry);
3191 genEntry[kGenSelectSpecies] = 1;
3192 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeKa[n];
3193 fhGenKa->Fill(genEntry);
3195 genEntry[kGenSelectSpecies] = 2;
3196 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePi[n];
3197 fhGenKa->Fill(genEntry);
3199 genEntry[kGenSelectSpecies] = 3;
3200 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePr[n];
3201 fhGenKa->Fill(genEntry);
3204 genEntry[kGenSelectSpecies] = 0;
3205 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeEl[n];
3206 fhGenPi->Fill(genEntry);
3208 genEntry[kGenSelectSpecies] = 1;
3209 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeKa[n];
3210 fhGenPi->Fill(genEntry);
3212 genEntry[kGenSelectSpecies] = 2;
3213 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePi[n];
3214 fhGenPi->Fill(genEntry);
3216 genEntry[kGenSelectSpecies] = 3;
3217 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePr[n];
3218 fhGenPi->Fill(genEntry);
3220 if (fTakeIntoAccountMuons) {
3221 // Muons, if desired
3222 genEntry[kGenSelectSpecies] = 0;
3223 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeEl[n];
3224 fhGenMu->Fill(genEntry);
3226 genEntry[kGenSelectSpecies] = 1;
3227 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeKa[n];
3228 fhGenMu->Fill(genEntry);
3230 genEntry[kGenSelectSpecies] = 2;
3231 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePi[n];
3232 fhGenMu->Fill(genEntry);
3234 genEntry[kGenSelectSpecies] = 3;
3235 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePr[n];
3236 fhGenMu->Fill(genEntry);
3240 genEntry[kGenSelectSpecies] = 0;
3241 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeEl[n];
3242 fhGenPr->Fill(genEntry);
3244 genEntry[kGenSelectSpecies] = 1;
3245 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeKa[n];
3246 fhGenPr->Fill(genEntry);
3248 genEntry[kGenSelectSpecies] = 2;
3249 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePi[n];
3250 fhGenPr->Fill(genEntry);
3252 genEntry[kGenSelectSpecies] = 3;
3253 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePr[n];
3254 fhGenPr->Fill(genEntry);
3258 printf("File: %s, Line: %d: ProcessTrack -> Done\n", (char*)__FILE__, __LINE__);
3264 //_____________________________________________________________________________
3265 Bool_t AliAnalysisTaskPID::SetConvolutedGaussLambdaParameter(Double_t lambda)
3267 // Set the lambda parameter of the convolution to the desired value. Automatically
3268 // calculates the parameters for the transition (restricted) gauss -> convoluted gauss.
3269 fConvolutedGaussTransitionPars[2] = lambda;
3271 // Save old parameters and settings of function to restore them later:
3272 Double_t* oldFuncParams = new Double_t[fkConvolutedGausNPar];
3273 for (Int_t i = 0; i < fkConvolutedGausNPar; i++)
3274 oldFuncParams[i] = fConvolutedGausDeltaPrime->GetParameter(i);
3275 Int_t oldFuncNpx = fConvolutedGausDeltaPrime->GetNpx();
3276 Double_t oldFuncRangeLow = 0, oldFuncRangeUp = 100;
3277 fConvolutedGausDeltaPrime->GetRange(oldFuncRangeLow, oldFuncRangeUp);
3279 // Choose some sufficiently large range
3280 const Double_t rangeStart = 0.5;
3281 const Double_t rangeEnd = 2.0;
3283 // To get the parameters for the transition, just choose arbitrarily input parameters for mu and sigma
3284 // (it makes sense to choose typical values). The ratio sigma_gauss / sigma_convolution is independent
3285 // of mu and as well the difference mu_gauss - mu_convolution.
3286 Double_t muInput = 1.0;
3287 Double_t sigmaInput = fgkSigmaReferenceForTransitionPars;
3290 // Step 1: Generate distribution with input parameters
3291 const Int_t nPar = 3;
3292 Double_t inputPar[nPar] = { muInput, sigmaInput, lambda };
3294 TH1D* hInput = new TH1D("hInput", "Input distribution", 2000, rangeStart, rangeEnd);
3296 fConvolutedGausDeltaPrime->SetParameters(inputPar);
3297 fConvolutedGausDeltaPrime->SetRange(rangeStart, rangeEnd);
3298 fConvolutedGausDeltaPrime->SetNpx(2000);
3301 // The resolution and mean of the AliPIDResponse are determined in finite intervals
3302 // of ncl (also second order effects due to finite dEdx and tanTheta).
3303 // Take this into account for the transition parameters via assuming an approximately flat
3304 // distritubtion in ncl in this interval.
3305 // NOTE: The ncl interval should be the same as the one used for the sigma map creation!
3306 const Int_t nclStart = 151;
3307 const Int_t nclEnd = 160;
3308 const Int_t nclSteps = (nclEnd - nclStart) + 1;
3309 for (Int_t ncl = nclStart; ncl <= nclEnd; ncl++) {
3310 // Resolution scales with 1/sqrt(ncl)
3311 fConvolutedGausDeltaPrime->SetParameter(1, inputPar[1] * sqrt(nclEnd) / sqrt(ncl));
3312 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3314 for (Int_t i = 0; i < 50000000 / nclSteps; i++)
3315 hInput->Fill(hProbDensity->GetRandom());
3319 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3321 for (Int_t i = 0; i < 50000000; i++)
3322 hInput->Fill(hProbDensity->GetRandom());
3324 // Step 2: Fit generated distribution with restricted gaussian
3325 Int_t maxBin = hInput->GetMaximumBin();
3326 Double_t max = hInput->GetBinContent(maxBin);
3328 UChar_t usedBins = 1;
3330 max += hInput->GetBinContent(maxBin - 1);
3333 if (maxBin < hInput->GetNbinsX()) {
3334 max += hInput->GetBinContent(maxBin + 1);
3339 // NOTE: The range (<-> fraction of maximum) should be the same
3340 // as for the spline and eta maps creation
3341 const Double_t lowThreshold = hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max));
3342 const Double_t highThreshold = hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max));
3344 TFitResultPtr fitResGaussFirstStep = hInput->Fit("gaus", "QNRS", "", lowThreshold, highThreshold);
3346 TFitResultPtr fitResGauss;
3348 if ((Int_t)fitResGaussFirstStep == 0) {
3349 TF1 fGauss("fGauss", "[0]*TMath::Gaus(x, [1], [2], 1)", rangeStart, rangeEnd);
3350 fGauss.SetParameter(0, fitResGaussFirstStep->GetParams()[0]);
3351 fGauss.SetParError(0, fitResGaussFirstStep->GetErrors()[0]);
3352 fGauss.SetParameter(2, fitResGaussFirstStep->GetParams()[2]);
3353 fGauss.SetParError(2, fitResGaussFirstStep->GetErrors()[2]);
3355 fGauss.FixParameter(1, fitResGaussFirstStep->GetParams()[1]);
3356 fitResGauss = hInput->Fit(&fGauss, "QNS", "s", rangeStart, rangeEnd);
3359 fitResGauss = hInput->Fit("gaus", "QNRS", "same", rangeStart, rangeEnd);
3361 //OLD TFitResultPtr fitResGauss = hInput->Fit("gaus", "QNRS", "", hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max)),
3362 // hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max)));
3365 // Step 3: Use parameters from gaussian fit to obtain parameters for the transition "restricted gauss" -> "convoluted gauss"
3367 // 3.1 The ratio sigmaInput / sigma_gaussFit ONLY depends on lambda (which is fixed per period) -> Calculate this first
3368 // for an arbitrary (here: typical) sigma. The ratio is then ~the same for ALL sigma for given lambda!
3369 if ((Int_t)fitResGauss != 0) {
3370 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Gauss Fit failed!\n");
3371 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3372 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3373 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3376 delete [] oldFuncParams;
3381 if (fitResGauss->GetParams()[2] <= 0) {
3382 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Sigma of gauss fit <= 0!\n");
3383 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3384 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3385 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3388 delete [] oldFuncParams;
3393 // sigma correction factor
3394 fConvolutedGaussTransitionPars[1] = sigmaInput / fitResGauss->GetParams()[2];
3396 // 3.2 Now that sigma und lambda are determined, one can calculate mu by shifting the maximum to the desired position,
3397 // i.e. the maximum of the input distribution should coincide with that of the re-calculated distribution,
3398 // which is achieved by getting the same mu for the same sigma.
3399 // NOTE: For fixed lambda, the shift is proportional to sigma and independent of mu!
3400 // So, one can calculate the shift for an arbitrary fixed (here: typical)
3401 // sigma and then simply use this shift for any other sigma by scaling it correspondingly!!!
3403 // Mu shift correction:
3404 // Shift in mu (difference between mean of gauss and mean of convolution) is proportional to sigma!
3405 // Thus, choose a reference sigma (typical -> 0.05), such that for arbitrary sigma one can simple scale
3406 // this shift correction with sigma / referenceSigma.
3407 fConvolutedGaussTransitionPars[0] = (fitResGauss->GetParams()[1] - muInput);
3410 /*Changed on 03.07.2013
3412 // Maximum of fConvolutedGausDeltaPrime should agree with maximum of input
3413 Double_t par[nPar] = { fitResGauss->GetParams()[1], // just as a guess of the maximum position
3417 fConvolutedGausDeltaPrime->SetParameters(par);
3419 Double_t maxXInput = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, muInput - 3. * sigmaInput),
3420 muInput + 10. * sigmaInput,
3423 // Maximum shifts proportional to sigma and is linear in mu (~mean of gauss)
3424 // Maximum should be typically located within [gaussMean, gaussMean + 3 gaussSigma].
3425 // -> Larger search range for safety reasons (also: sigma and/or mean might be not 100% accurate).
3426 Double_t maxXconvoluted = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001,
3427 fitResGauss->GetParams()[1] - 3. * fitResGauss->GetParams()[2]),
3428 fitResGauss->GetParams()[1] + 10. * fitResGauss->GetParams()[2],
3430 if (maxXconvoluted <= 0) {
3431 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Maximum of fConvolutedGausDeltaPrime <= 0!\n");
3433 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3434 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3435 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3438 delete [] oldFuncParams;
3443 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX to input value.
3444 // Mu shift correction:
3445 fConvolutedGaussTransitionPars[0] = maxXconvoluted - maxXInput;
3450 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3451 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3452 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3455 delete [] oldFuncParams;
3461 //_____________________________________________________________________________
3462 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::SetParamsForConvolutedGaus(Double_t gausMean, Double_t gausSigma)
3464 // Set parameters for convoluted gauss using parameters for a pure gaussian.
3465 // If SetConvolutedGaussLambdaParameter has not been called before to initialise the translation parameters,
3466 // some default parameters will be used and an error will show up.
3469 printf("File: %s, Line: %d: SetParamsForConvolutedGaus: mean %e, sigma %e\n", (char*)__FILE__, __LINE__, gausMean, gausSigma);
3471 if (fConvolutedGaussTransitionPars[1] < -998) {
3472 AliError("Transition parameters not initialised! Default parameters will be used. Please call SetConvolutedGaussLambdaParameter(...) before any calculations!");
3473 SetConvolutedGaussLambdaParameter(2.0);
3474 AliError(Form("Parameters set to:\n[0]: %f\n[1]: %f\n[2]: %f\n", fConvolutedGaussTransitionPars[0],
3475 fConvolutedGaussTransitionPars[1], fConvolutedGaussTransitionPars[2]));
3478 Double_t par[fkConvolutedGausNPar];
3479 par[2] = fConvolutedGaussTransitionPars[2];
3480 par[1] = fConvolutedGaussTransitionPars[1] * gausSigma;
3481 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX so that it sits at the right place.
3482 par[0] = gausMean - fConvolutedGaussTransitionPars[0] * par[1] / fgkSigmaReferenceForTransitionPars;
3484 ErrorCode errCode = kNoErrors;
3485 fConvolutedGausDeltaPrime->SetParameters(par);
3488 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> Parameters set to: %e, %e, %e (transition pars: %e, %e, %e, %e)\n",
3489 (char*)__FILE__, __LINE__, par[0], par[1], par[2], fConvolutedGaussTransitionPars[0], fConvolutedGaussTransitionPars[1],
3490 fConvolutedGaussTransitionPars[2], fgkSigmaReferenceForTransitionPars);
3492 fConvolutedGausDeltaPrime->SetNpx(20); // Small value speeds up following algorithm (valid, since extrema far apart)
3494 // Accuracy of 10^-5 is enough to get 0.1% precise peak for MIPS w.r.t. to dEdx = 2000 of protons
3495 // (should boost up the algorithm, because 10^-10 is the default value!)
3496 Double_t maxX= fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, gausMean - 2. * gausSigma),
3497 gausMean + 6. * gausSigma, 1.0E-5);
3499 const Double_t maximum = fConvolutedGausDeltaPrime->Eval(maxX);
3500 const Double_t maximumFraction = maximum * fAccuracyNonGaussianTail;
3502 // Estimate lower boundary for subsequent search:
3503 Double_t lowBoundSearchBoundLow = TMath::Max(1e-4, maxX - 5. * gausSigma);
3504 Double_t lowBoundSearchBoundUp = maxX;
3506 Bool_t lowerBoundaryFixedAtZero = kFALSE;
3508 while (fConvolutedGausDeltaPrime->Eval(lowBoundSearchBoundLow) >= maximumFraction) {
3509 if (lowBoundSearchBoundLow <= 0) {
3510 // This should only happen to low dEdx particles with very few clusters and therefore large sigma, such that the gauss goes below zero deltaPrime
3511 if (maximum <= 0) { // Something is weired
3512 printf("Error generating signal: maximum is <= 0!\n");
3516 const Double_t valueAtZero = fConvolutedGausDeltaPrime->Eval(0);
3517 if (valueAtZero / maximum > 0.05) {
3518 // Too large fraction below zero deltaPrime. Signal generation cannot be reliable in this case
3519 printf("Error generating signal: Too large fraction below zero deltaPrime: convGauss(0) / convGauss(max) = %e / %e = %e!\n",
3520 valueAtZero, maximum, valueAtZero / maximum);
3526 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",
3527 fConvolutedGausDeltaPrime->Eval(maxX), fAccuracyNonGaussianTail, maximumFraction, maxX, par[0], par[1], par[2], gausMean, gausSigma);
3530 lowerBoundaryFixedAtZero = kTRUE;
3532 if (errCode != kError)
3538 lowBoundSearchBoundUp -= gausSigma;
3539 lowBoundSearchBoundLow -= gausSigma;
3541 if (lowBoundSearchBoundLow < 0) {
3542 lowBoundSearchBoundLow = 0;
3543 lowBoundSearchBoundUp += gausSigma;
3547 // Determine lower boundary inside estimated range. For small values of the maximum: Need more precision, since finer binning!
3548 Double_t rangeStart = lowerBoundaryFixedAtZero ? 0 :
3549 fConvolutedGausDeltaPrime->GetX(maximumFraction, lowBoundSearchBoundLow, lowBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3551 // .. and the same for the upper boundary
3552 Double_t rangeEnd = 0;
3553 // If distribution starts beyond upper boundary, everything ends up in the overflow bin. So, just reduce range and Npx to minimum
3554 if (rangeStart > fkDeltaPrimeUpLimit) {
3555 rangeEnd = rangeStart + 0.00001;
3556 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3557 fConvolutedGausDeltaPrime->SetNpx(4);
3560 // Estimate upper boundary for subsequent search:
3561 Double_t upBoundSearchBoundUp = maxX + 5 * gausSigma;
3562 Double_t upBoundSearchBoundLow = maxX;
3563 while (fConvolutedGausDeltaPrime->Eval(upBoundSearchBoundUp) >= maximumFraction) {
3564 upBoundSearchBoundUp += gausSigma;
3565 upBoundSearchBoundLow += gausSigma;
3568 // For small values of the maximum: Need more precision, since finer binning!
3569 rangeEnd = fConvolutedGausDeltaPrime->GetX(maximumFraction, upBoundSearchBoundLow, upBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3571 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3572 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3574 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3575 //fConvolutedGausDeltaPrime->SetNpx(fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeEnd)
3576 // - fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeStart) + 1);
3577 //fConvolutedGausDeltaPrime->SetNpx((rangeEnd - rangeStart) / fDeltaPrimeBinWidth + 1);
3581 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> range %f - %f, error code %d\n", (char*)__FILE__, __LINE__,
3582 rangeStart, rangeEnd, errCode);
3588 //________________________________________________________________________
3589 void AliAnalysisTaskPID::SetUpGenHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3591 // Sets bin limits for axes which are not standard binned and the axes titles.
3593 hist->SetBinEdges(kGenPt, binsPt);
3594 hist->SetBinEdges(kGenDeltaPrimeSpecies, binsDeltaPrime);
3595 hist->SetBinEdges(kGenCentrality, binsCent);
3597 if (fStoreAdditionalJetInformation)
3598 hist->SetBinEdges(kGenJetPt, binsJetPt);
3601 hist->GetAxis(kGenMCID)->SetTitle("MC PID");
3602 hist->GetAxis(kGenMCID)->SetBinLabel(1, "e");
3603 hist->GetAxis(kGenMCID)->SetBinLabel(2, "K");
3604 hist->GetAxis(kGenMCID)->SetBinLabel(3, "#mu");
3605 hist->GetAxis(kGenMCID)->SetBinLabel(4, "#pi");
3606 hist->GetAxis(kGenMCID)->SetBinLabel(5, "p");
3608 hist->GetAxis(kGenSelectSpecies)->SetTitle("Select Species");
3609 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(1, "e");
3610 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(2, "K");
3611 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(3, "#pi");
3612 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(4, "p");
3614 hist->GetAxis(kGenPt)->SetTitle("p_{T} (GeV/c)");
3616 hist->GetAxis(kGenDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3618 hist->GetAxis(kGenCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3620 if (fStoreAdditionalJetInformation) {
3621 hist->GetAxis(kGenJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3623 hist->GetAxis(kGenZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3625 hist->GetAxis(kGenXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3628 hist->GetAxis(GetIndexOfChargeAxisGen())->SetTitle("Charge (e_{0})");
3630 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetTitle("TOF PID Info");
3631 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3632 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3633 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3634 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3635 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3636 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3640 //________________________________________________________________________
3641 void AliAnalysisTaskPID::SetUpGenYieldHist(THnSparse* hist, Double_t* binsPt, Double_t* binsCent, Double_t* binsJetPt) const
3643 // Sets bin limits for axes which are not standard binned and the axes titles.
3645 hist->SetBinEdges(kGenYieldPt, binsPt);
3646 hist->SetBinEdges(kGenYieldCentrality, binsCent);
3647 if (fStoreAdditionalJetInformation)
3648 hist->SetBinEdges(kGenYieldJetPt, binsJetPt);
3650 for (Int_t i = 0; i < 5; i++)
3651 hist->GetAxis(kGenYieldMCID)->SetBinLabel(i + 1, AliPID::ParticleLatexName(i));
3654 hist->GetAxis(kGenYieldMCID)->SetTitle("MC PID");
3655 hist->GetAxis(kGenYieldPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3656 hist->GetAxis(kGenYieldCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3658 if (fStoreAdditionalJetInformation) {
3659 hist->GetAxis(kGenYieldJetPt)->SetTitle("p_{T}^{jet, gen} (GeV/c)");
3661 hist->GetAxis(kGenYieldZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3663 hist->GetAxis(kGenYieldXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3666 hist->GetAxis(GetIndexOfChargeAxisGenYield())->SetTitle("Charge (e_{0})");
3670 //________________________________________________________________________
3671 void AliAnalysisTaskPID::SetUpHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3673 // Sets bin limits for axes which are not standard binned and the axes titles.
3675 hist->SetBinEdges(kDataPt, binsPt);
3676 hist->SetBinEdges(kDataDeltaPrimeSpecies, binsDeltaPrime);
3677 hist->SetBinEdges(kDataCentrality, binsCent);
3679 if (fStoreAdditionalJetInformation)
3680 hist->SetBinEdges(kDataJetPt, binsJetPt);
3683 hist->GetAxis(kDataMCID)->SetTitle("MC PID");
3684 hist->GetAxis(kDataMCID)->SetBinLabel(1, "e");
3685 hist->GetAxis(kDataMCID)->SetBinLabel(2, "K");
3686 hist->GetAxis(kDataMCID)->SetBinLabel(3, "#mu");
3687 hist->GetAxis(kDataMCID)->SetBinLabel(4, "#pi");
3688 hist->GetAxis(kDataMCID)->SetBinLabel(5, "p");
3690 hist->GetAxis(kDataSelectSpecies)->SetTitle("Select Species");
3691 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(1, "e");
3692 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(2, "K");
3693 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(3, "#pi");
3694 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(4, "p");
3696 hist->GetAxis(kDataPt)->SetTitle("p_{T} (GeV/c)");
3698 hist->GetAxis(kDataDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3700 hist->GetAxis(kDataCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3702 if (fStoreAdditionalJetInformation) {
3703 hist->GetAxis(kDataJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3705 hist->GetAxis(kDataZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3707 hist->GetAxis(kDataXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3710 hist->GetAxis(GetIndexOfChargeAxisData())->SetTitle("Charge (e_{0})");
3712 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetTitle("TOF PID Info");
3713 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3714 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3715 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3716 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3717 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3718 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3722 //________________________________________________________________________
3723 void AliAnalysisTaskPID::SetUpPtResHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt, Double_t* binsCent) const
3725 // Sets bin limits for axes which are not standard binned and the axes titles.
3727 hist->SetBinEdges(kPtResJetPt, binsJetPt);
3728 hist->SetBinEdges(kPtResGenPt, binsPt);
3729 hist->SetBinEdges(kPtResRecPt, binsPt);
3730 hist->SetBinEdges(kPtResCentrality, binsCent);
3733 hist->GetAxis(kPtResJetPt)->SetTitle("p_{T}^{jet, rec} (GeV/c)");
3734 hist->GetAxis(kPtResGenPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3735 hist->GetAxis(kPtResRecPt)->SetTitle("p_{T}^{rec} (GeV/c)");
3737 hist->GetAxis(kPtResCharge)->SetTitle("Charge (e_{0})");
3738 hist->GetAxis(kPtResCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3742 //________________________________________________________________________
3743 void AliAnalysisTaskPID::SetUpSharedClsHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt) const
3745 // Sets bin limits for axes which are not standard binned and the axes titles.
3747 hist->SetBinEdges(kQASharedClsJetPt, binsJetPt);
3748 hist->SetBinEdges(kQASharedClsPt, binsPt);
3751 hist->GetAxis(kQASharedClsJetPt)->SetTitle("#it{p}_{T}^{jet} (GeV/#it{c})");
3752 hist->GetAxis(kQASharedClsPt)->SetTitle("#it{p}_{T} (GeV/#it{c})");
3753 hist->GetAxis(kQASharedClsNumSharedCls)->SetTitle("#it{N}_{shared}^{cls}");
3754 hist->GetAxis(kQASharedClsPadRow)->SetTitle("Pad row");
3759 //________________________________________________________________________
3760 void AliAnalysisTaskPID::SetUpDeDxCheckHist(THnSparse* hist, const Double_t* binsPt, const Double_t* binsJetPt, const Double_t* binsEtaAbs) const
3762 // Sets bin limits for axes which are not standard binned and the axes titles.
3763 hist->SetBinEdges(kDeDxCheckP, binsPt);
3764 hist->SetBinEdges(kDeDxCheckJetPt, binsJetPt);
3765 hist->SetBinEdges(kDeDxCheckEtaAbs, binsEtaAbs);
3769 hist->GetAxis(kDeDxCheckPID)->SetTitle("PID");
3770 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(1, "e");
3771 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(2, "K");
3772 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(3, "#pi");
3773 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(4, "p");
3776 hist->GetAxis(kDeDxCheckJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3777 hist->GetAxis(kDeDxCheckEtaAbs)->SetTitle("|#eta|");
3778 hist->GetAxis(kDeDxCheckP)->SetTitle("p_{TPC} (GeV/c)");
3779 hist->GetAxis(kDeDxCheckDeDx)->SetTitle("TPC dE/dx (arb. unit)");
3783 //________________________________________________________________________
3784 void AliAnalysisTaskPID::SetUpBinZeroStudyHist(THnSparse* hist, const Double_t* binsCent, const Double_t* binsPt) const
3786 // Sets bin limits for axes which are not standard binned and the axes titles.
3787 hist->SetBinEdges(kBinZeroStudyCentrality, binsCent);
3788 hist->SetBinEdges(kBinZeroStudyGenPt, binsPt);
3791 hist->GetAxis(kBinZeroStudyCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3792 hist->GetAxis(kBinZeroStudyGenEta)->SetTitle("#it{#eta}^{gen}");
3793 hist->GetAxis(kBinZeroStudyGenPt)->SetTitle("#it{p}_{T}^{gen} (GeV/#it{c})");