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 Bool_t useITSTPCtrackletsCentEstimatorWithNewBinning = fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0
601 && fStoreCentralityPercentile;
603 const Int_t nCentBinsGeneral = 12;
604 const Int_t nCentBinsNewITSTPCtracklets = 17;
606 const Int_t nCentBins = useITSTPCtrackletsCentEstimatorWithNewBinning ? nCentBinsNewITSTPCtracklets : nCentBinsGeneral;
608 Double_t binsCent[nCentBins+1];
609 for (Int_t i = 0; i < nCentBins + 1; i++)
612 //-1 for pp (unless explicitely requested); 90-100 has huge electro-magnetic impurities
613 Double_t binsCentV0[nCentBinsGeneral+1] = {-1, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
615 // These centrality estimators deal with integers! This implies that the ranges are always [lowlim, uplim - 1]
616 Double_t binsCentITSTPCTracklets[nCentBinsNewITSTPCtracklets+1] = { -9999, 0, 1, 4, 7, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 9999 };
617 Double_t binsCentITSTPCTrackletsOldPreliminary[nCentBinsGeneral+1] = { 0, 7, 13, 20, 29, 40, 50, 60, 72, 83, 95, 105, 115 };
619 // Special centrality binning for pp
620 Double_t binsCentpp[nCentBinsGeneral+1] = { 0, 0.01, 0.1, 1, 5, 10, 15, 20, 30, 40, 50, 70, 100};
622 if (fCentralityEstimator.CompareTo("ITSTPCtrackletsOldPreliminaryBinning", TString::kIgnoreCase) == 0 && fStoreCentralityPercentile) {
623 // Special binning for this centrality estimator; but keep number of bins!
624 for (Int_t i = 0; i < nCentBinsGeneral+1; i++)
625 binsCent[i] = binsCentITSTPCTrackletsOldPreliminary[i];
627 else if (fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0 && fStoreCentralityPercentile) {
628 // Special binning for this centrality estimator and different number of bins!
629 for (Int_t i = 0; i < nCentBinsNewITSTPCtracklets+1; i++)
630 binsCent[i] = binsCentITSTPCTracklets[i];
632 else if (fCentralityEstimator.Contains("ppMult", TString::kIgnoreCase) && fStoreCentralityPercentile) {
633 // Special binning for this pp centrality estimator; but keep number of bins!
634 for (Int_t i = 0; i < nCentBinsGeneral+1; i++)
635 binsCent[i] = binsCentpp[i];
638 // Take default binning for VZERO
639 for (Int_t i = 0; i < nCentBinsGeneral+1; i++)
640 binsCent[i] = binsCentV0[i];
643 const Int_t nJetPtBins = 11;
644 Double_t binsJetPt[nJetPtBins+1] = {0, 2, 5, 10, 15, 20, 30, 40, 60, 80, 120, 200};
646 const Int_t nChargeBins = 2;
647 const Double_t binsCharge[nChargeBins+1] = { -1.0 - 1e-4, 0.0, 1.0 + 1e-4 };
649 const Int_t nBinsJets = kDataNumAxes;
650 const Int_t nBinsNoJets = nBinsJets - fgkNumJetAxes;
652 const Int_t nBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
654 // deltaPrimeSpecies binning
655 const Int_t deltaPrimeNBins = 600;
656 Double_t deltaPrimeBins[deltaPrimeNBins + 1];
658 const Double_t fromLow = fkDeltaPrimeLowLimit;
659 const Double_t toHigh = fkDeltaPrimeUpLimit;
660 const Double_t factor = TMath::Power(toHigh/fromLow, 1./deltaPrimeNBins);
662 // Log binning for whole deltaPrime range
663 deltaPrimeBins[0] = fromLow;
664 for (Int_t i = 0 + 1; i <= deltaPrimeNBins; i++) {
665 deltaPrimeBins[i] = factor * deltaPrimeBins[i - 1];
668 fDeltaPrimeAxis = new TAxis(deltaPrimeNBins, deltaPrimeBins);
670 const Int_t nMCPIDbins = 5;
671 const Double_t mcPIDmin = 0.;
672 const Double_t mcPIDmax = 5.;
674 const Int_t nSelSpeciesBins = 4;
675 const Double_t selSpeciesMin = 0.;
676 const Double_t selSpeciesMax = 4.;
678 const Int_t nZBins = 20;
679 const Double_t zMin = 0.;
680 const Double_t zMax = 1.;
682 const Int_t nXiBins = 70;
683 const Double_t xiMin = 0.;
684 const Double_t xiMax = 7.;
686 const Int_t nTOFpidInfoBins = kNumTOFpidInfoBins;
687 const Double_t tofPIDinfoMin = kNoTOFinfo;
688 const Double_t tofPIDinfoMax = kNoTOFinfo + kNumTOFpidInfoBins;
690 // MC PID, SelectSpecies, pT, deltaPrimeSpecies, centrality percentile, jet pT, z = track_pT/jet_pT, xi = log(1/z)
691 Int_t binsNoJets[nBinsNoJets] = { nMCPIDbins,
699 Int_t binsJets[nBinsJets] = { nMCPIDbins,
710 Int_t *bins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
712 Double_t xminNoJets[nBinsNoJets] = { mcPIDmin,
720 Double_t xminJets[nBinsJets] = { mcPIDmin,
731 Double_t *xmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
733 Double_t xmaxNoJets[nBinsNoJets] = { mcPIDmax,
736 deltaPrimeBins[deltaPrimeNBins],
738 binsCharge[nChargeBins],
741 Double_t xmaxJets[nBinsJets] = { mcPIDmax,
744 deltaPrimeBins[deltaPrimeNBins],
746 binsJetPt[nJetPtBins],
749 binsCharge[nChargeBins],
752 Double_t *xmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
754 fConvolutedGausDeltaPrime->SetNpx(deltaPrimeNBins);
757 fhPIDdataAll = new THnSparseD("hPIDdataAll","", nBins, bins, xmin, xmax);
758 SetUpHist(fhPIDdataAll, binsPt, deltaPrimeBins, binsCent, binsJetPt);
759 fOutputContainer->Add(fhPIDdataAll);
762 // Generated histograms (so far, bins are the same as for primary THnSparse)
763 const Int_t nGenBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
764 // MC PID, SelectSpecies, Pt, deltaPrimeSpecies, jet pT, z = track_pT/jet_pT, xi = log(1/z)
766 Int_t *genBins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
767 Double_t *genXmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
768 Double_t *genXmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
771 fhGenEl = new THnSparseD("hGenEl", "", nGenBins, genBins, genXmin, genXmax);
772 SetUpGenHist(fhGenEl, binsPt, deltaPrimeBins, binsCent, binsJetPt);
773 fOutputContainer->Add(fhGenEl);
775 fhGenKa = new THnSparseD("hGenKa", "", nGenBins, genBins, genXmin, genXmax);
776 SetUpGenHist(fhGenKa, binsPt, deltaPrimeBins, binsCent, binsJetPt);
777 fOutputContainer->Add(fhGenKa);
779 fhGenPi = new THnSparseD("hGenPi", "", nGenBins, genBins, genXmin, genXmax);
780 SetUpGenHist(fhGenPi, binsPt, deltaPrimeBins, binsCent, binsJetPt);
781 fOutputContainer->Add(fhGenPi);
783 if (fTakeIntoAccountMuons) {
784 fhGenMu = new THnSparseD("hGenMu", "", nGenBins, genBins, genXmin, genXmax);
785 SetUpGenHist(fhGenMu, binsPt, deltaPrimeBins, binsCent, binsJetPt);
786 fOutputContainer->Add(fhGenMu);
789 fhGenPr = new THnSparseD("hGenPr", "", nGenBins, genBins, genXmin, genXmax);
790 SetUpGenHist(fhGenPr, binsPt, deltaPrimeBins, binsCent, binsJetPt);
791 fOutputContainer->Add(fhGenPr);
795 fhEventsProcessed = new TH1D("fhEventsProcessed",
796 "Number of events passing trigger selection, vtx and zvtx cuts and pile-up rejection;Centrality Percentile",
797 nCentBins, binsCent);
798 fhEventsProcessed->Sumw2();
799 fOutputContainer->Add(fhEventsProcessed);
801 fhEventsTriggerSelVtxCut = new TH1D("fhEventsTriggerSelVtxCut",
802 "Number of events passing trigger selection and vtx cut;Centrality Percentile",
803 nCentBins, binsCent);
804 fhEventsTriggerSelVtxCut->Sumw2();
805 fOutputContainer->Add(fhEventsTriggerSelVtxCut);
807 fhEventsTriggerSel = new TH1D("fhEventsTriggerSel",
808 "Number of events passing trigger selection;Centrality Percentile",
809 nCentBins, binsCent);
810 fOutputContainer->Add(fhEventsTriggerSel);
811 fhEventsTriggerSel->Sumw2();
814 fhEventsProcessedNoPileUpRejection = new TH1D("fhEventsProcessedNoPileUpRejection",
815 "Number of events passing trigger selection, vtx and zvtx cuts;Centrality Percentile",
816 nCentBins, binsCent);
817 fOutputContainer->Add(fhEventsProcessedNoPileUpRejection);
818 fhEventsProcessedNoPileUpRejection->Sumw2();
821 // Generated yields within acceptance
822 const Int_t nBinsGenYields = fStoreAdditionalJetInformation ? kGenYieldNumAxes : kGenYieldNumAxes - 3;
823 Int_t genYieldsBins[kGenYieldNumAxes] = { nMCPIDbins, nPtBins, nCentBins, nJetPtBins, nZBins, nXiBins,
825 genYieldsBins[GetIndexOfChargeAxisGenYield()] = nChargeBins;
826 Double_t genYieldsXmin[kGenYieldNumAxes] = { mcPIDmin, binsPt[0], binsCent[0], binsJetPt[0], zMin, xiMin,
828 genYieldsXmin[GetIndexOfChargeAxisGenYield()] = binsCharge[0];
829 Double_t genYieldsXmax[kGenYieldNumAxes] = { mcPIDmax, binsPt[nPtBins], binsCent[nCentBins], binsJetPt[nJetPtBins], zMax, xiMax,
830 binsCharge[nChargeBins] };
831 genYieldsXmax[GetIndexOfChargeAxisGenYield()] = binsCharge[nChargeBins];
834 fhMCgeneratedYieldsPrimaries = new THnSparseD("fhMCgeneratedYieldsPrimaries",
835 "Generated yields w/o reco and cuts inside acceptance (physical primaries)",
836 nBinsGenYields, genYieldsBins, genYieldsXmin, genYieldsXmax);
837 SetUpGenYieldHist(fhMCgeneratedYieldsPrimaries, binsPt, binsCent, binsJetPt);
838 fOutputContainer->Add(fhMCgeneratedYieldsPrimaries);
841 // Container with several process steps (generated and reconstructed level with some variations)
846 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(2) successful\n", (char*)__FILE__, __LINE__);
848 // Array for the number of bins in each dimension
849 // Dimensions: MC-ID, trackPt, trackEta, trackCharge, cenrality percentile, jetPt, z, xi TODO phi???
850 const Int_t nEffDims = fStoreAdditionalJetInformation ? kEffNumAxes : kEffNumAxes - 3; // Number of dimensions for the efficiency
852 const Int_t nMCIDbins = AliPID::kSPECIES;
853 Double_t binsMCID[nMCIDbins + 1];
855 for(Int_t i = 0; i <= nMCIDbins; i++) {
859 const Int_t nEtaBins = 18;
860 const Double_t binsEta[nEtaBins+1] = {-0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
861 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };
863 const Int_t nEffBins[kEffNumAxes] = { nMCIDbins, nPtBins, nEtaBins, nChargeBins, nCentBins, nJetPtBins, nZBins, nXiBins };
865 fContainerEff = new AliCFContainer("containerEff", "Reconstruction Efficiency x Acceptance x Resolution and Secondary Correction",
866 kNumSteps, nEffDims, nEffBins);
868 // Setting the bin limits
869 fContainerEff->SetBinLimits(kEffMCID, binsMCID);
870 fContainerEff->SetBinLimits(kEffTrackPt, binsPt);
871 fContainerEff->SetBinLimits(kEffTrackEta, binsEta);
872 fContainerEff->SetBinLimits(kEffTrackCharge, binsCharge);
873 fContainerEff->SetBinLimits(kEffCentrality, binsCent);
874 if (fStoreAdditionalJetInformation) {
875 fContainerEff->SetBinLimits(kEffJetPt, binsJetPt);
876 fContainerEff->SetBinLimits(kEffZ, zMin, zMax);
877 fContainerEff->SetBinLimits(kEffXi, xiMin, xiMax);
880 fContainerEff->SetVarTitle(kEffMCID,"MC ID");
881 fContainerEff->SetVarTitle(kEffTrackPt,"p_{T} (GeV/c)");
882 fContainerEff->SetVarTitle(kEffTrackEta,"#eta");
883 fContainerEff->SetVarTitle(kEffTrackCharge,"Charge (e_{0})");
884 fContainerEff->SetVarTitle(kEffCentrality, "Centrality Percentile");
885 if (fStoreAdditionalJetInformation) {
886 fContainerEff->SetVarTitle(kEffJetPt, "p_{T}^{jet} (GeV/c)");
887 fContainerEff->SetVarTitle(kEffZ, "z = p_{T}^{track} / p_{T}^{jet}");
888 fContainerEff->SetVarTitle(kEffXi, "#xi = ln(p_{T}^{jet} / p_{T}^{track})");
891 // Define clean MC sample
892 fContainerEff->SetStepTitle(kStepGenWithGenCuts, "Particle level, cuts on particle level");
893 // For Acceptance x Efficiency correction of primaries
894 fContainerEff->SetStepTitle(kStepRecWithGenCuts, "Detector level (rec) with cuts on particle level");
895 // For (pT) resolution correction
896 fContainerEff->SetStepTitle(kStepRecWithGenCutsMeasuredObs,
897 "Detector level (rec) with cuts on particle level with measured observables");
898 // For secondary correction
899 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObs,
900 "Detector level, all cuts on detector level with measured observables");
901 fContainerEff->SetStepTitle(kStepRecWithRecCutsPrimaries,
902 "Detector level, all cuts on detector level, only MC primaries");
903 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsPrimaries,
904 "Detector level, all cuts on detector level with measured observables, only MC primaries");
905 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsStrangenessScaled,
906 "Detector level (strangeness scaled), all cuts on detector level with measured observables");
909 if (fDoPID || fDoEfficiency) {
911 fh2FFJetPtRec = new TH2D("fh2FFJetPtRec", "Number of reconstructed jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
912 nCentBins, binsCent, nJetPtBins, binsJetPt);
913 fh2FFJetPtRec->Sumw2();
914 fOutputContainer->Add(fh2FFJetPtRec);
915 fh2FFJetPtGen = new TH2D("fh2FFJetPtGen", "Number of generated jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
916 nCentBins, binsCent, nJetPtBins, binsJetPt);
917 fh2FFJetPtGen->Sumw2();
918 fOutputContainer->Add(fh2FFJetPtGen);
921 // Pythia information
922 fh1Xsec = new TProfile("fh1Xsec", "xsec from pyxsec.root", 1, 0, 1);
924 fh1Xsec->GetXaxis()->SetBinLabel(1, "<#sigma>");
925 fh1Trials = new TH1D("fh1Trials", "trials from pyxsec.root", 1, 0, 1);
927 fh1Trials->GetXaxis()->SetBinLabel(1, "#sum{ntrials}");
929 fOutputContainer->Add(fh1Xsec);
930 fOutputContainer->Add(fh1Trials);
932 if (fDoDeDxCheck || fDoPtResolution) {
934 fQAContainer = new TObjArray(1);
935 fQAContainer->SetName(Form("%s_QA", GetName()));
936 fQAContainer->SetOwner(kTRUE);
939 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(3) successful\n", (char*)__FILE__, __LINE__);
942 if (fDoPtResolution) {
943 const Int_t nPtBinsRes = 100;
944 Double_t pTbinsRes[nPtBinsRes + 1];
946 const Double_t fromLowPtRes = 0.15;
947 const Double_t toHighPtRes = 50.;
948 const Double_t factorPtRes = TMath::Power(toHighPtRes/fromLowPtRes, 1./nPtBinsRes);
949 // Log binning for whole pT range
950 pTbinsRes[0] = fromLowPtRes;
951 for (Int_t i = 0 + 1; i <= nPtBinsRes; i++) {
952 pTbinsRes[i] = factorPtRes * pTbinsRes[i - 1];
955 const Int_t nBinsPtResolution = kPtResNumAxes;
956 Int_t ptResolutionBins[kPtResNumAxes] = { nJetPtBins, nPtBinsRes, nPtBinsRes,
957 nChargeBins, nCentBins };
958 Double_t ptResolutionXmin[kPtResNumAxes] = { binsJetPt[0], pTbinsRes[0], pTbinsRes[0],
959 binsCharge[0], binsCent[0] };
960 Double_t ptResolutionXmax[kPtResNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], pTbinsRes[nPtBinsRes],
961 binsCharge[nChargeBins], binsCent[nCentBins] };
963 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
964 fPtResolution[i] = new THnSparseD(Form("fPtResolution_%s", AliPID::ParticleShortName(i)),
965 Form("Pt resolution for primaries, %s", AliPID::ParticleLatexName(i)),
966 nBinsPtResolution, ptResolutionBins, ptResolutionXmin, ptResolutionXmax);
967 SetUpPtResHist(fPtResolution[i], pTbinsRes, binsJetPt, binsCent);
968 fQAContainer->Add(fPtResolution[i]);
972 // Besides the pT resolution, also perform check on shared clusters
973 const Int_t nBinsQASharedCls = kQASharedClsNumAxes;
974 Int_t qaSharedClsBins[kQASharedClsNumAxes] = { nJetPtBins, nPtBinsRes, 160, 160 };
975 Double_t qaSharedClsXmin[kQASharedClsNumAxes] = { binsJetPt[0], pTbinsRes[0], 0, -1 };
976 Double_t qaSharedClsXmax[kQASharedClsNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], 160, 159 };
978 fQASharedCls = new THnSparseD("fQASharedCls", "QA shared clusters", nBinsQASharedCls, qaSharedClsBins, qaSharedClsXmin, qaSharedClsXmax);
980 SetUpSharedClsHist(fQASharedCls, pTbinsRes, binsJetPt);
981 fQAContainer->Add(fQASharedCls);
987 const Int_t nEtaAbsBins = 9;
988 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 };
990 const Double_t dEdxMin = 20;
991 const Double_t dEdxMax = 110;
992 const Int_t nDeDxBins = (Int_t) ((dEdxMax - dEdxMin) / 0.02);
993 const Int_t nBinsDeDxCheck= kDeDxCheckNumAxes;
994 Int_t dEdxCheckBins[kDeDxCheckNumAxes] = { nSelSpeciesBins, nPtBins, nJetPtBins, nEtaAbsBins, nDeDxBins };
995 Double_t dEdxCheckXmin[kDeDxCheckNumAxes] = { selSpeciesMin, binsPt[0], binsJetPt[0], binsEtaAbs[0], dEdxMin };
996 Double_t dEdxCheckXmax[kDeDxCheckNumAxes] = { selSpeciesMax, binsPt[nPtBins], binsJetPt[nJetPtBins], binsEtaAbs[nEtaAbsBins], dEdxMax };
998 fDeDxCheck = new THnSparseD("fDeDxCheck", "dEdx check", nBinsDeDxCheck, dEdxCheckBins, dEdxCheckXmin, dEdxCheckXmax);
999 SetUpDeDxCheckHist(fDeDxCheck, binsPt, binsJetPt, binsEtaAbs);
1000 fQAContainer->Add(fDeDxCheck);
1003 if (fDoBinZeroStudy) {
1004 const Double_t etaLow = -0.9;
1005 const Double_t etaUp = 0.9;
1006 const Int_t nEtaBins = 18;
1008 const Int_t nBinsBinZeroStudy = kBinZeroStudyNumAxes;
1009 Int_t binZeroStudyBins[nBinsBinZeroStudy] = { nCentBins, nPtBins, nEtaBins };
1010 Double_t binZeroStudyXmin[nBinsBinZeroStudy] = { binsCent[0], binsPt[0], etaLow };
1011 Double_t binZeroStudyXmax[nBinsBinZeroStudy] = { binsCent[nCentBins], binsPt[nPtBins], etaUp };
1013 fChargedGenPrimariesTriggerSel = new THnSparseD("fChargedGenPrimariesTriggerSel", "Trigger sel.", nBinsBinZeroStudy, binZeroStudyBins,
1014 binZeroStudyXmin, binZeroStudyXmax);
1015 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSel, binsCent, binsPt);
1016 fOutputContainer->Add(fChargedGenPrimariesTriggerSel);
1018 fChargedGenPrimariesTriggerSelVtxCut = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCut", "Vertex cut", nBinsBinZeroStudy,
1019 binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1020 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCut, binsCent, binsPt);
1021 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCut);
1023 fChargedGenPrimariesTriggerSelVtxCutZ = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCutZ", "Vertex #it{z} cut", nBinsBinZeroStudy,
1024 binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1025 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCutZ, binsCent, binsPt);
1026 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCutZ);
1028 fChargedGenPrimariesTriggerSelVtxCutZPileUpRej = new THnSparseD("fChargedGenPrimariesTriggerSelVtxCutZPileUpRej", "Vertex #it{z} cut",
1029 nBinsBinZeroStudy, binZeroStudyBins, binZeroStudyXmin, binZeroStudyXmax);
1030 SetUpBinZeroStudyHist(fChargedGenPrimariesTriggerSelVtxCutZPileUpRej, binsCent, binsPt);
1031 fOutputContainer->Add(fChargedGenPrimariesTriggerSelVtxCutZPileUpRej);
1035 printf("File: %s, Line: %d: UserCreateOutputObjects -> Posting output data\n", (char*)__FILE__, __LINE__);
1037 PostData(1, fOutputContainer);
1039 PostData(2, fContainerEff);
1040 if (fDoDeDxCheck || fDoPtResolution)
1041 PostData(3, fQAContainer);
1044 printf("File: %s, Line: %d: UserCreateOutputObjects -> Done\n", (char*)__FILE__, __LINE__);
1048 //________________________________________________________________________
1049 void AliAnalysisTaskPID::UserExec(Option_t *)
1052 // Called for each event
1055 printf("File: %s, Line: %d: UserExec\n", (char*)__FILE__, __LINE__);
1057 // No processing of event, if input is fed in directly from another task
1058 if (fInputFromOtherTask)
1062 printf("File: %s, Line: %d: UserExec -> Processing started\n", (char*)__FILE__, __LINE__);
1064 fEvent = dynamic_cast<AliVEvent*>(InputEvent());
1066 Printf("ERROR: fEvent not available");
1070 ConfigureTaskForCurrentEvent(fEvent);
1072 fMC = dynamic_cast<AliMCEvent*>(MCEvent());
1074 if (!fPIDResponse || !fPIDcombined)
1077 Double_t centralityPercentile = -1;
1078 if (fStoreCentralityPercentile) {
1079 if (fCentralityEstimator.Contains("ITSTPCtracklets", TString::kIgnoreCase)) {
1080 // Special pp centrality estimator
1081 AliESDEvent* esdEvent = dynamic_cast<AliESDEvent*>(fEvent);
1083 AliError("Not esd event -> Cannot use tracklet multiplicity estimator!");
1084 centralityPercentile = -1;
1087 centralityPercentile = AliESDtrackCuts::GetReferenceMultiplicity(esdEvent, AliESDtrackCuts::kTrackletsITSTPC, fEtaAbsCutUp);
1089 else if (fCentralityEstimator.Contains("ppMult", TString::kIgnoreCase)) {
1090 // Another special pp centrality estimator
1091 centralityPercentile = fAnaUtils->GetMultiplicityPercentile(fEvent, GetPPCentralityEstimator().Data());
1094 // Ordinary centrality estimator
1095 centralityPercentile = fEvent->GetCentrality()->GetCentralityPercentile(fCentralityEstimator.Data());
1099 // Check if vertex is ok, but don't apply cut on z position
1100 const Bool_t passedVertexSelection = GetVertexIsOk(fEvent, kFALSE);
1101 // Now check again, but also require z position to be in desired range
1102 const Bool_t passedVertexZSelection = GetVertexIsOk(fEvent, kTRUE);
1104 const Bool_t isPileUp = GetIsPileUp(fEvent, fPileUpRejectionType);
1108 if (fDoBinZeroStudy && fMC) {
1109 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1110 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1115 if (!fMC->IsPhysicalPrimary(iPart))
1118 const Double_t etaGen = mcPart->Eta();
1119 const Double_t ptGen = mcPart->Pt();
1121 Double_t values[kBinZeroStudyNumAxes] = { 0. };
1122 values[kBinZeroStudyCentrality] = centralityPercentile;
1123 values[kBinZeroStudyGenPt] = ptGen;
1124 values[kBinZeroStudyGenEta] = etaGen;
1126 fChargedGenPrimariesTriggerSel->Fill(values);
1127 if (passedVertexSelection) {
1128 fChargedGenPrimariesTriggerSelVtxCut->Fill(values);
1129 if (passedVertexZSelection) {
1130 fChargedGenPrimariesTriggerSelVtxCutZ->Fill(values);
1132 fChargedGenPrimariesTriggerSelVtxCutZPileUpRej->Fill(values);
1141 // Event counters for trigger selection, vertex cuts and pile-up rejection
1142 IncrementEventCounter(centralityPercentile, kTriggerSel);
1144 if (!passedVertexSelection)
1147 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCut);
1149 if (!passedVertexZSelection)
1152 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCutNoPileUpRejection);
1153 // ATTENTION: Is this the right place for the pile-up rejection? Important to have still the proper bin-0 correction,
1154 // which is done solely with sel and selVtx, since the zvtx selection does ~not change the spectra. The question is whether the pile-up
1155 // 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
1156 // of events. But if it does change the spectra, this must somehow be corrected for.
1157 // NOTE: multiplicity >= 0 usually implies a properly reconstructed vertex. Hence, the bin-0 correction cannot be done in multiplicity bins.
1158 // Furthermore, there seems to be no MC simulation with pile-up rejection, so the bin-0 correction cannot be extracted with it. Pile-up
1159 // rejection has only a minor impact, so maybe there is no need to dig further.
1163 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCut);
1165 Double_t magField = fEvent->GetMagneticField();
1168 if (fDoPID || fDoEfficiency) {
1169 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1170 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1175 // Define clean MC sample with corresponding particle level track cuts:
1176 // - MC-track must be in desired eta range
1177 // - MC-track must be physical primary
1178 // - Species must be one of those in question (everything else goes to the overflow bin of mcID)
1180 // Geometrie should be the same as on the reconstructed level -> By definition analysis within this eta interval
1181 if (!IsInAcceptedEtaRange(TMath::Abs(mcPart->Eta()))) continue;
1183 Int_t mcID = PDGtoMCID(mcPart->PdgCode());
1185 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1186 Double_t chargeMC = mcPart->Charge() / 3.;
1188 if (TMath::Abs(chargeMC) < 0.01)
1189 continue; // Reject neutral particles (only relevant, if mcID is not used)
1191 if (!fMC->IsPhysicalPrimary(iPart))
1195 Double_t valuesGenYield[kGenYieldNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), centralityPercentile, -1, -1, -1, -1 };
1196 valuesGenYield[GetIndexOfChargeAxisGenYield()] = chargeMC;
1198 fhMCgeneratedYieldsPrimaries->Fill(valuesGenYield);
1202 if (fDoEfficiency) {
1203 Double_t valueEff[kEffNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), mcPart->Eta(), chargeMC, centralityPercentile,
1206 fContainerEff->Fill(valueEff, kStepGenWithGenCuts);
1212 // Track loop to fill a Train spectrum
1213 for (Int_t iTracks = 0; iTracks < fEvent->GetNumberOfTracks(); iTracks++) {
1214 AliVTrack* track = dynamic_cast<AliVTrack*>(fEvent->GetTrack(iTracks));
1216 Printf("ERROR: Could not retrieve track %d", iTracks);
1221 // Apply detector level track cuts
1222 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
1223 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
1224 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
1228 if(fTrackFilter && !fTrackFilter->IsSelected(track))
1231 if (GetUseTPCCutMIGeo()) {
1232 if (!TPCCutMIGeo(track, fEvent))
1235 else if (GetUseTPCnclCut()) {
1236 if (!TPCnclCut(track))
1241 if (!PhiPrimeCut(track, magField))
1242 continue; // reject track
1245 Int_t pdg = 0; // = 0 indicates data for the moment
1246 AliMCParticle* mcTrack = 0x0;
1247 Int_t mcID = AliPID::kUnknown;
1251 label = track->GetLabel();
1256 mcTrack = dynamic_cast<AliMCParticle*>(fMC->GetTrack(TMath::Abs(label)));
1258 Printf("ERROR: Could not retrieve mcTrack with label %d for track %d", label, iTracks);
1262 pdg = mcTrack->PdgCode();
1263 mcID = PDGtoMCID(mcTrack->PdgCode());
1265 if (fDoEfficiency) {
1266 // For efficiency: Reconstructed track has survived all cuts on the detector level (excluding acceptance)
1267 // and has an associated MC track which is a physical primary and was generated inside the acceptance
1268 if (fMC->IsPhysicalPrimary(TMath::Abs(label)) &&
1269 IsInAcceptedEtaRange(TMath::Abs(mcTrack->Eta()))) {
1271 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1272 Double_t value[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3., centralityPercentile,
1274 fContainerEff->Fill(value, kStepRecWithGenCuts);
1276 Double_t valueMeas[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1278 fContainerEff->Fill(valueMeas, kStepRecWithGenCutsMeasuredObs);
1283 // Only process tracks inside the desired eta window
1284 if (!IsInAcceptedEtaRange(TMath::Abs(track->Eta()))) continue;
1286 if (fDoPID || fDoDeDxCheck || fDoPtResolution)
1287 ProcessTrack(track, pdg, centralityPercentile, -1); // No jet information in this case -> Set jet pT to -1
1289 if (fDoPtResolution) {
1290 if (mcTrack && fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1291 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1292 Double_t valuePtRes[kPtResNumAxes] = { -1, mcTrack->Pt(), track->Pt(), mcTrack->Charge() / 3., centralityPercentile };
1293 FillPtResolution(mcID, valuePtRes);
1297 if (fDoEfficiency) {
1299 Double_t valueRecAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1301 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObs);
1303 Double_t weight = IsSecondaryWithStrangeMotherMC(fMC, TMath::Abs(label)) ?
1304 GetMCStrangenessFactorCMS(fMC, mcTrack) : 1.0;
1305 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsStrangenessScaled, weight);
1307 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1308 Double_t valueGenAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3.,
1309 centralityPercentile, -1, -1, -1 };
1310 if (fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1311 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsPrimaries);
1312 fContainerEff->Fill(valueGenAllCuts, kStepRecWithRecCutsPrimaries);
1319 printf("File: %s, Line: %d: UserExec -> Processing done\n", (char*)__FILE__, __LINE__);
1324 printf("File: %s, Line: %d: UserExec -> Done\n", (char*)__FILE__, __LINE__);
1327 //________________________________________________________________________
1328 void AliAnalysisTaskPID::Terminate(const Option_t *)
1330 // Draw result to the screen
1331 // Called once at the end of the query
1335 //_____________________________________________________________________________
1336 void AliAnalysisTaskPID::CheckDoAnyStematicStudiesOnTheExpectedSignal()
1338 // Check whether at least one scale factor indicates the ussage of systematic studies
1339 // and set internal flag accordingly.
1341 fDoAnySystematicStudiesOnTheExpectedSignal = kFALSE;
1344 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
1345 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
1346 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1350 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1351 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1352 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1356 if ((TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
1357 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon)) {
1358 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1362 if (TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
1363 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1369 //_____________________________________________________________________________
1370 void AliAnalysisTaskPID::ConfigureTaskForCurrentEvent(AliVEvent* event)
1372 // Configure the task for the current event. In particular, this is needed if the run number changes
1375 AliError("Could not set up task: no event!");
1379 Int_t run = event->GetRunNumber();
1382 // If systematics on eta is investigated, need to calculate the maxEtaVariationMap
1383 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1384 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1385 if (!CalculateMaxEtaVariationMapFromPIDResponse())
1386 AliFatal("Systematics on eta correction requested, but failed to calculate max eta varation map!");
1394 //_____________________________________________________________________________
1395 Int_t AliAnalysisTaskPID::PDGtoMCID(Int_t pdg)
1397 // Returns the corresponding AliPID index to the given pdg code.
1398 // Returns AliPID::kUnkown if pdg belongs to a not considered species.
1400 Int_t absPDGcode = TMath::Abs(pdg);
1401 if (absPDGcode == 211) {//Pion
1402 return AliPID::kPion;
1404 else if (absPDGcode == 321) {//Kaon
1405 return AliPID::kKaon;
1407 else if (absPDGcode == 2212) {//Proton
1408 return AliPID::kProton;
1410 else if (absPDGcode == 11) {//Electron
1411 return AliPID::kElectron;
1413 else if (absPDGcode == 13) {//Muon
1414 return AliPID::kMuon;
1417 return AliPID::kUnknown;
1421 //_____________________________________________________________________________
1422 void AliAnalysisTaskPID::GetJetTrackObservables(Double_t trackPt, Double_t jetPt, Double_t& z, Double_t& xi)
1424 // Uses trackPt and jetPt to obtain z and xi.
1426 z = (jetPt > 0 && trackPt >= 0) ? (trackPt / jetPt) : -1;
1427 xi = (z > 0) ? TMath::Log(1. / z) : -1;
1429 if(trackPt > (1. - 1e-06) * jetPt && trackPt < (1. + 1e-06) * jetPt) { // case z=1 : move entry to last histo bin <1
1436 //_____________________________________________________________________________
1437 void AliAnalysisTaskPID::CleanupParticleFractionHistos()
1439 // Delete histos with particle fractions
1441 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1442 delete fFractionHists[i];
1443 fFractionHists[i] = 0x0;
1445 delete fFractionSysErrorHists[i];
1446 fFractionSysErrorHists[i] = 0x0;
1451 //_____________________________________________________________________________
1452 Double_t AliAnalysisTaskPID::ConvolutedGaus(const Double_t* xx, const Double_t* par) const
1454 // Convolutes gauss with an exponential tail which describes dEdx-response better than pure gaussian
1456 const Double_t mean = par[0];
1457 const Double_t sigma = par[1];
1458 const Double_t lambda = par[2];
1461 printf("File: %s, Line: %d: ConvolutedGaus: mean %e, sigma %e, lambda %e\n", (char*)__FILE__, __LINE__, mean, sigma, lambda);
1463 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);
1467 //_____________________________________________________________________________
1468 inline Double_t AliAnalysisTaskPID::FastGaus(Double_t x, Double_t mean, Double_t sigma) const
1470 // Calculate an unnormalised gaussian function with mean and sigma.
1472 if (sigma < fgkEpsilon)
1475 const Double_t arg = (x - mean) / sigma;
1476 return exp(-0.5 * arg * arg);
1480 //_____________________________________________________________________________
1481 inline Double_t AliAnalysisTaskPID::FastNormalisedGaus(Double_t x, Double_t mean, Double_t sigma) const
1483 // Calculate a normalised (divided by sqrt(2*Pi)*sigma) gaussian function with mean and sigma.
1485 if (sigma < fgkEpsilon)
1488 const Double_t arg = (x - mean) / sigma;
1489 const Double_t res = exp(-0.5 * arg * arg);
1490 return res / (2.50662827463100024 * sigma); //sqrt(2*Pi)=2.50662827463100024
1494 //_____________________________________________________________________________
1495 Int_t AliAnalysisTaskPID::FindBinWithinRange(TAxis* axis, Double_t value) const
1497 // Find the corresponding bin of the axis. Values outside the range (also under and overflow) will be set to the first/last
1500 Int_t bin = axis->FindFixBin(value);
1504 if (bin > axis->GetNbins())
1505 bin = axis->GetNbins();
1511 //_____________________________________________________________________________
1512 Int_t AliAnalysisTaskPID::FindFirstBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1515 // Kind of projects a TH3 to 1 bin combination in y and z
1516 // and looks for the first x bin above a threshold for this projection.
1517 // If no such bin is found, -1 is returned.
1522 Int_t nBinsX = hist->GetNbinsX();
1523 for (Int_t xBin = 1; xBin <= nBinsX; xBin++) {
1524 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1532 //_____________________________________________________________________________
1533 Int_t AliAnalysisTaskPID::FindLastBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1536 // Kind of projects a TH3 to 1 bin combination in y and z
1537 // and looks for the last x bin above a threshold for this projection.
1538 // If no such bin is found, -1 is returned.
1543 Int_t nBinsX = hist->GetNbinsX();
1544 for (Int_t xBin = nBinsX; xBin >= 1; xBin--) {
1545 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1553 //_____________________________________________________________________________
1554 Bool_t AliAnalysisTaskPID::GetParticleFraction(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1555 AliPID::EParticleType species,
1556 Double_t& fraction, Double_t& fractionErrorStat, Double_t& fractionErrorSys) const
1558 // Computes the particle fraction for the corresponding species for the given trackPt, jetPt and centrality.
1559 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1560 // On success (return value kTRUE), fraction contains the particle fraction, fractionErrorStat(Sys) the sigma of its
1561 // statistical (systematic) error
1564 fractionErrorStat = 999.;
1565 fractionErrorSys = 999.;
1567 if (species > AliPID::kProton || species < AliPID::kElectron) {
1568 AliError(Form("Only fractions for species index %d to %d availabe, but not for the requested one: %d", 0, AliPID::kProton, species));
1572 if (!fFractionHists[species]) {
1573 AliError(Form("Histo with particle fractions for species %d not loaded!", species));
1578 Int_t jetPtBin = FindBinWithinRange(fFractionHists[species]->GetYaxis(), jetPt);
1579 Int_t centBin = FindBinWithinRange(fFractionHists[species]->GetZaxis(), centralityPercentile);
1581 // The following interpolation takes the bin content of the first/last available bin,
1582 // if requested point lies beyond bin center of first/last bin.
1583 // The interpolation is only done for the x-axis (track pT), i.e. jetPtBin and centBin are fix,
1584 // because the analysis will anyhow be run in bins of jetPt and centrality and
1585 // it is not desired to correlate different jetPt bins via interpolation.
1587 // The same procedure is used for the error of the fraction
1588 TAxis* xAxis = fFractionHists[species]->GetXaxis();
1590 // No interpolation to values beyond the centers of the first/last bins (we don't know exactly where the spectra start or stop,
1591 // thus, search for the first and last bin above 0.0 to constrain the range
1592 Int_t firstBin = TMath::Max(1, FindFirstBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1593 Int_t lastBin = TMath::Min(fFractionHists[species]->GetNbinsX(),
1594 FindLastBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1596 if (trackPt <= xAxis->GetBinCenter(firstBin)) {
1597 fraction = fFractionHists[species]->GetBinContent(firstBin, jetPtBin, centBin);
1598 fractionErrorStat = fFractionHists[species]->GetBinError(firstBin, jetPtBin, centBin);
1599 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(firstBin, jetPtBin, centBin) : 0.;
1601 else if (trackPt >= xAxis->GetBinCenter(lastBin)) {
1602 fraction = fFractionHists[species]->GetBinContent(lastBin, jetPtBin, centBin);
1603 fractionErrorStat = fFractionHists[species]->GetBinError(lastBin, jetPtBin, centBin);
1604 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(lastBin, jetPtBin, centBin) : 0.;
1607 Double_t x0 = 0., x1 = 0., y0 = 0., y1 = 0.;
1608 Double_t y0errStat = 0., y1errStat = 0., y0errSys = 0., y1errSys = 0.;
1609 Int_t trackPtBin = xAxis->FindFixBin(trackPt);
1611 // Linear interpolation between nearest neighbours in trackPt
1612 if (trackPt <= xAxis->GetBinCenter(trackPtBin)) {
1613 y0 = fFractionHists[species]->GetBinContent(trackPtBin - 1, jetPtBin, centBin);
1614 y0errStat = fFractionHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin);
1615 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin)
1617 x0 = xAxis->GetBinCenter(trackPtBin - 1);
1618 y1 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1619 y1errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1620 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1622 x1 = xAxis->GetBinCenter(trackPtBin);
1625 y0 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1626 y0errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1627 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1629 x0 = xAxis->GetBinCenter(trackPtBin);
1630 y1 = fFractionHists[species]->GetBinContent(trackPtBin + 1, jetPtBin, centBin);
1631 y1errStat = fFractionHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin);
1632 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin)
1634 x1 = xAxis->GetBinCenter(trackPtBin + 1);
1637 // Per construction: x0 < trackPt < x1
1638 fraction = y0 + (trackPt - x0) * ((y1 - y0) / (x1 - x0));
1639 fractionErrorStat = y0errStat + (trackPt - x0) * ((y1errStat - y0errStat) / (x1 - x0));
1640 fractionErrorSys = fFractionSysErrorHists[species] ? (y0errSys + (trackPt - x0) * ((y1errSys - y0errSys) / (x1 - x0))) : 0.;
1647 //_____________________________________________________________________________
1648 Bool_t AliAnalysisTaskPID::GetParticleFractions(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1649 Double_t* prob, Int_t smearSpeciesByError,
1650 Int_t takeIntoAccountSpeciesSysError, Bool_t uniformSystematicError) const
1652 // Fills the particle fractions for the given trackPt, jetPt and centrality into "prob".
1653 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1654 // If smearSpeciesByError is >= 0 && < AliPID::kSPECIES, the returned fractions will be a random number distributed
1655 // with a gauss with mean being the corresponding particle fraction and sigma it's error for the considered species
1656 // "smearSpeciesByError".
1657 // Note that in this case the fractions for all species will NOT sum up to 1!
1658 // Thus, all other species fractions will be re-scaled weighted with their corresponding statistical error.
1659 // A similar procedure is used for "takeIntoAccountSpeciesSysError": The systematic error of the corresponding species
1660 // is used to generate a random number with uniform distribution in [mean - sysError, mean + sysError] for the new mean
1661 // (in cace of uniformSystematicError = kTRUE, otherwise it will be a gaus(mean, sysError)),
1662 // then the other species will be re-scaled according to their systematic errors.
1663 // First, the systematic error uncertainty procedure will be performed (that is including re-scaling), then the statistical
1664 // uncertainty procedure.
1665 // On success, kTRUE is returned.
1667 if (!prob || smearSpeciesByError >= AliPID::kSPECIES || takeIntoAccountSpeciesSysError >= AliPID::kSPECIES)
1670 Double_t probTemp[AliPID::kSPECIES];
1671 Double_t probErrorStat[AliPID::kSPECIES];
1672 Double_t probErrorSys[AliPID::kSPECIES];
1674 Bool_t success = kTRUE;
1675 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kElectron,
1676 probTemp[AliPID::kElectron], probErrorStat[AliPID::kElectron],
1677 probErrorSys[AliPID::kElectron]);
1678 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kMuon,
1679 probTemp[AliPID::kMuon], probErrorStat[AliPID::kMuon], probErrorSys[AliPID::kMuon]);
1680 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kPion,
1681 probTemp[AliPID::kPion], probErrorStat[AliPID::kPion], probErrorSys[AliPID::kPion]);
1682 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kKaon,
1683 probTemp[AliPID::kKaon], probErrorStat[AliPID::kKaon], probErrorSys[AliPID::kKaon]);
1684 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kProton,
1685 probTemp[AliPID::kProton], probErrorStat[AliPID::kProton], probErrorSys[AliPID::kProton]);
1690 // If desired, take into account the systematic error of the corresponding species and re-generate probTemp accordingly
1691 if (takeIntoAccountSpeciesSysError >= 0) {
1692 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1693 Double_t generatedFraction = uniformSystematicError
1694 ? fRandom->Rndm() * 2. * probErrorSys[takeIntoAccountSpeciesSysError]
1695 - probErrorSys[takeIntoAccountSpeciesSysError]
1696 + probTemp[takeIntoAccountSpeciesSysError]
1697 : fRandom->Gaus(probTemp[takeIntoAccountSpeciesSysError],
1698 probErrorSys[takeIntoAccountSpeciesSysError]);
1700 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1701 if (generatedFraction < 0.)
1702 generatedFraction = 0.;
1703 else if (generatedFraction > 1.)
1704 generatedFraction = 1.;
1706 // Calculate difference from original fraction (original fractions sum up to 1!)
1707 Double_t deltaFraction = generatedFraction - probTemp[takeIntoAccountSpeciesSysError];
1709 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1710 if (deltaFraction > 0) {
1711 // Some part will be SUBTRACTED from the other fractions
1712 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1713 if (probTemp[i] - probErrorSys[i] < 0)
1714 probErrorSys[i] = probTemp[i];
1718 // Some part will be ADDED to the other fractions
1719 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1720 if (probTemp[i] + probErrorSys[i] > 1)
1721 probErrorSys[i] = 1. - probTemp[i];
1725 // Compute summed weight of all fractions except for the considered one
1726 Double_t summedWeight = 0.;
1727 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1728 if (i != takeIntoAccountSpeciesSysError)
1729 summedWeight += probErrorSys[i];
1732 // Compute the weight for the other species
1734 if (summedWeight <= 1e-13) {
1735 // If this happens for some reason (it should not!), just assume flat weight
1736 printf("Error: summedWeight (sys error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1737 trackPt, jetPt, centralityPercentile);
1740 Double_t weight[AliPID::kSPECIES];
1741 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1742 if (i != takeIntoAccountSpeciesSysError) {
1743 if (summedWeight > 1e-13)
1744 weight[i] = probErrorSys[i] / summedWeight;
1746 weight[i] = probErrorSys[i] / (AliPID::kSPECIES - 1);
1750 // For the final generated fractions, set the generated value for the considered species
1751 // and the generated value minus delta times statistical weight
1752 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1753 if (i != takeIntoAccountSpeciesSysError)
1754 probTemp[i] = probTemp[i] - weight[i] * deltaFraction;
1756 probTemp[i] = generatedFraction;
1760 // Using the values of probTemp (either the original ones or those after taking into account the systematic error),
1761 // calculate the final fractions - if the statistical error is to be taken into account, smear the corresponding
1762 // fraction. If not, just write probTemp to the final result array.
1763 if (smearSpeciesByError >= 0) {
1764 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1765 Double_t generatedFraction = fRandom->Gaus(probTemp[smearSpeciesByError], probErrorStat[smearSpeciesByError]);
1767 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1768 if (generatedFraction < 0.)
1769 generatedFraction = 0.;
1770 else if (generatedFraction > 1.)
1771 generatedFraction = 1.;
1773 // Calculate difference from original fraction (original fractions sum up to 1!)
1774 Double_t deltaFraction = generatedFraction - probTemp[smearSpeciesByError];
1776 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1777 if (deltaFraction > 0) {
1778 // Some part will be SUBTRACTED from the other fractions
1779 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1780 if (probTemp[i] - probErrorStat[i] < 0)
1781 probErrorStat[i] = probTemp[i];
1785 // Some part will be ADDED to the other fractions
1786 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1787 if (probTemp[i] + probErrorStat[i] > 1)
1788 probErrorStat[i] = 1. - probTemp[i];
1792 // Compute summed weight of all fractions except for the considered one
1793 Double_t summedWeight = 0.;
1794 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1795 if (i != smearSpeciesByError)
1796 summedWeight += probErrorStat[i];
1799 // Compute the weight for the other species
1801 if (summedWeight <= 1e-13) {
1802 // If this happens for some reason (it should not!), just assume flat weight
1803 printf("Error: summedWeight (stat error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1804 trackPt, jetPt, centralityPercentile);
1807 Double_t weight[AliPID::kSPECIES];
1808 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1809 if (i != smearSpeciesByError) {
1810 if (summedWeight > 1e-13)
1811 weight[i] = probErrorStat[i] / summedWeight;
1813 weight[i] = probErrorStat[i] / (AliPID::kSPECIES - 1);
1817 // For the final generated fractions, set the generated value for the considered species
1818 // and the generated value minus delta times statistical weight
1819 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1820 if (i != smearSpeciesByError)
1821 prob[i] = probTemp[i] - weight[i] * deltaFraction;
1823 prob[i] = generatedFraction;
1827 // Just take the generated values
1828 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
1829 prob[i] = probTemp[i];
1833 // Should already be normalised, but make sure that it really is:
1834 Double_t probSum = 0.;
1835 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1842 if (TMath::Abs(probSum - 1.0) > 1e-4) {
1843 printf("Warning: Re-normalising sum of fractions: Sum is %e\n", probSum);
1844 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1853 //_____________________________________________________________________________
1854 const TH3D* AliAnalysisTaskPID::GetParticleFractionHisto(Int_t species, Bool_t sysError) const
1856 if (species < AliPID::kElectron || species > AliPID::kProton)
1859 return sysError ? fFractionSysErrorHists[species] : fFractionHists[species];
1863 //_____________________________________________________________________________
1864 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(Int_t motherPDG, Double_t motherGenPt)
1866 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1867 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction, which uses
1868 // the following data from CMS pp @ 7 TeV inclusive (JHEP 05 (2011) 064)
1872 const Int_t absMotherPDG = TMath::Abs(motherPDG);
1874 if (absMotherPDG == 310 || absMotherPDG == 321) { // K0s / K+ / K-
1875 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.768049;
1876 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.732933;
1877 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.650298;
1878 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.571332;
1879 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.518734;
1880 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.492543;
1881 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.482704;
1882 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.488056;
1883 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.488861;
1884 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.492862;
1885 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.504332;
1886 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.501858;
1887 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.512970;
1888 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.524131;
1889 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.539130;
1890 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.554101;
1891 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.560348;
1892 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.568869;
1893 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.583310;
1894 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.604818;
1895 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.632630;
1896 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.710070;
1897 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.736365;
1898 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 0.835865;
1901 if (absMotherPDG == 3122) { // Lambda
1902 //if (absMotherPDG == 3122 || absMotherPDG == 3112 || absMotherPDG == 3222) { // Lambda / Sigma- / Sigma+
1903 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.645162;
1904 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.627431;
1905 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.457136;
1906 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.384369;
1907 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.330597;
1908 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.309571;
1909 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.293620;
1910 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.283709;
1911 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.282047;
1912 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.277261;
1913 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.275772;
1914 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.280726;
1915 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.288540;
1916 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.288315;
1917 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.296619;
1918 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.302993;
1919 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.338121;
1920 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.349800;
1921 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.356802;
1922 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.391202;
1923 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.422573;
1924 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.573815;
1925 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.786984;
1926 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 1.020021;
1929 if (absMotherPDG == 3312 || absMotherPDG == 3322) { // xi
1930 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.666620;
1931 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.575908;
1932 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.433198;
1933 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.340901;
1934 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.290896;
1935 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.236074;
1936 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.218681;
1937 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.207763;
1938 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.222848;
1939 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.208806;
1940 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.197275;
1941 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.183645;
1942 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.188788;
1943 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.188282;
1944 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.207442;
1945 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.240388;
1946 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.241916;
1947 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.208276;
1948 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.234550;
1949 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.251689;
1950 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.310204;
1951 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.343492;
1954 const Double_t weight = 1. / fac;
1960 //_____________________________________________________________________________
1961 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(AliMCEvent* mcEvent, AliMCParticle* daughter)
1963 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1964 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction
1969 AliMCParticle* currentMother = daughter;
1970 AliMCParticle* currentDaughter = daughter;
1973 // find first primary mother K0s, Lambda or Xi
1975 Int_t daughterPDG = currentDaughter->PdgCode();
1977 Int_t motherLabel = currentDaughter->GetMother();
1978 if(motherLabel >= mcEvent->GetNumberOfTracks()){ // protection
1979 currentMother = currentDaughter;
1983 currentMother = (AliMCParticle*)mcEvent->GetTrack(motherLabel);
1985 if (!currentMother) {
1986 currentMother = currentDaughter;
1990 Int_t motherPDG = currentMother->PdgCode();
1992 // phys. primary found ?
1993 if (mcEvent->IsPhysicalPrimary(motherLabel))
1996 if (TMath::Abs(daughterPDG) == 321) {
1997 // K+/K- e.g. from phi (ref data not feeddown corrected)
1998 currentMother = currentDaughter;
2001 if (TMath::Abs(motherPDG) == 310) {
2002 // K0s e.g. from phi (ref data not feeddown corrected)
2005 if (TMath::Abs(motherPDG) == 3212 && TMath::Abs(daughterPDG) == 3122) {
2006 // Mother Sigma0, daughter Lambda (this case not included in feeddown corr.)
2007 currentMother = currentDaughter;
2011 currentDaughter = currentMother;
2015 Int_t motherPDG = currentMother->PdgCode();
2016 Double_t motherGenPt = currentMother->Pt();
2018 return GetMCStrangenessFactorCMS(motherPDG, motherGenPt);
2022 // _________________________________________________________________________________
2023 AliAnalysisTaskPID::TOFpidInfo AliAnalysisTaskPID::GetTOFType(const AliVTrack* track, Int_t tofMode) const
2025 // Get the (locally defined) particle type judged by TOF
2027 if (!fPIDResponse) {
2028 Printf("ERROR: fPIDResponse not available -> Cannot determine TOF type!");
2032 /*TODO still needs some further thinking how to implement it....
2033 // TOF PID status (kTOFout, kTIME) automatically checked by return value of ComputeTPCProbability;
2034 // also, probability array will be set there (no need to initialise here)
2035 Double_t p[AliPID::kSPECIES];
2036 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->ComputeTPCProbability(track, AliPID::kSPECIES, p);
2037 if (tofStatus != AliPIDResponse::kDetPidOk)
2040 // Do not consider muons
2041 p[AliPID::kMuon] = 0.;
2043 // Probabilities are not normalised yet
2045 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2051 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2054 Double_t probThreshold = -999.;
2056 // If there is only one distribution, the threshold corresponds to...
2060 else if (tofMode == 1) { // default
2061 probThreshold = 0.9973; // a 3-sigma inclusion cut
2063 else if (tofMode == 2) {
2068 Printf("ERROR: Bad TOF mode: %d!", tofMode);
2074 ///* OLD: cut with n-sigmas (ATTENTION: Does not take into account properly the TOF tail!)
2075 // Check kTOFout, kTIME, mismatch
2076 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->CheckPIDStatus(AliPIDResponse::kTOF, track);
2077 if (tofStatus != AliPIDResponse::kDetPidOk)
2080 Double_t nsigma[kNumTOFspecies + 1] = { -999., -999., -999., -999. };
2081 nsigma[kTOFpion] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kPion);
2082 nsigma[kTOFkaon] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kKaon);
2083 nsigma[kTOFproton] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton);
2085 Double_t inclusion = -999;
2086 Double_t exclusion = -999;
2092 else if (tofMode == 1) { // default
2096 else if (tofMode == 2) {
2101 Printf("ERROR: Bad TOF mode: %d!", tofMode);
2105 // Do not cut on nSigma electron because this would also remove pions in a large pT range.
2106 // The electron contamination of the pion sample can be treated by TPC dEdx fits afterwards.
2107 if (TMath::Abs(nsigma[kTOFpion]) < inclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
2109 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) < inclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
2111 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) < inclusion)
2115 // There are no TOF electrons selected because the purity is rather bad, even for small momenta
2116 // (also a small mismatch probability significantly affects electrons because their fraction
2117 // is small). There is no need for TOF electrons anyway, since the dEdx distribution of kaons and
2118 // protons in a given pT bin (also at the dEdx crossings) is very different from that of electrons.
2119 // This is due to the steeply falling dEdx of p and K with momentum, whereas the electron dEdx stays
2121 // As a result, the TPC fit yields a more accurate electron fraction than the TOF selection can do.
2127 // _________________________________________________________________________________
2128 Bool_t AliAnalysisTaskPID::IsSecondaryWithStrangeMotherMC(AliMCEvent* mcEvent, Int_t partLabel)
2130 // Check whether particle is a secondary with strange mother, i.e. returns kTRUE if a strange mother is found
2131 // and the particle is NOT a physical primary. In all other cases kFALSE is returned
2133 if (!mcEvent || partLabel < 0)
2136 AliMCParticle* part = (AliMCParticle*)mcEvent->GetTrack(partLabel);
2141 if (mcEvent->IsPhysicalPrimary(partLabel))
2144 Int_t iMother = part->GetMother();
2149 AliMCParticle* partM = (AliMCParticle*)mcEvent->GetTrack(iMother);
2153 Int_t codeM = TMath::Abs(partM->PdgCode());
2154 Int_t mfl = Int_t(codeM / TMath::Power(10, Int_t(TMath::Log10(codeM))));
2155 if (mfl == 3 && codeM != 3) // codeM = 3 is for s quark
2162 //_____________________________________________________________________________
2163 Bool_t AliAnalysisTaskPID::SetParticleFractionHisto(const TH3D* hist, Int_t species, Bool_t sysError)
2165 // Store a clone of hist (containing the particle fractions of the corresponding species with statistical error (sysError = kFALSE)
2166 // or systematic error (sysError = kTRUE), respectively), internally
2168 if (species < AliPID::kElectron || species > AliPID::kProton) {
2169 AliError(Form("Only fractions for species index %d to %d can be set, but not for the requested one: %d", 0,
2170 AliPID::kProton, species));
2175 delete fFractionSysErrorHists[species];
2177 fFractionSysErrorHists[species] = new TH3D(*hist);
2180 delete fFractionHists[species];
2182 fFractionHists[species] = new TH3D(*hist);
2189 //_____________________________________________________________________________
2190 Bool_t AliAnalysisTaskPID::SetParticleFractionHistosFromFile(const TString filePathName, Bool_t sysError)
2192 // Loads particle fractions for all species from the desired file and returns kTRUE on success.
2193 // The maps are assumed to be of Type TH3D, to sit in the main directory and to have names
2194 // Form("hFraction_%e", AliPID::ParticleName(i)) for sysError = kFALSE and
2195 // Form("hFractionSysError_%e", AliPID::ParticleName(i)) for sysError = kTRUE.
2197 TFile* f = TFile::Open(filePathName.Data());
2199 std::cout << "Failed to open file with particle fractions \"" << filePathName.Data() << "\"!" << std::endl;
2204 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
2205 TString histName = Form("hFraction%s_%s", sysError ? "SysError" : "", AliPID::ParticleName(i));
2206 hist = dynamic_cast<TH3D*>(f->Get(histName.Data()));
2208 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2209 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2210 CleanupParticleFractionHistos();
2214 if (!SetParticleFractionHisto(hist, i, sysError)) {
2215 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2216 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2217 CleanupParticleFractionHistos();
2229 //_____________________________________________________________________________
2230 Double_t AliAnalysisTaskPID::GetMaxEtaVariation(Double_t dEdxSplines)
2232 // Returns the maximum eta variation (i.e. deviation of eta correction factor from unity) for the
2233 // given (spline) dEdx
2235 if (dEdxSplines < 1. || !fhMaxEtaVariation) {
2236 Printf("Error GetMaxEtaVariation: No map or invalid dEdxSplines (%f)!", dEdxSplines);
2240 Int_t bin = fhMaxEtaVariation->GetXaxis()->FindFixBin(1. / dEdxSplines);
2244 if (bin > fhMaxEtaVariation->GetXaxis()->GetNbins())
2245 bin = fhMaxEtaVariation->GetXaxis()->GetNbins();
2247 return fhMaxEtaVariation->GetBinContent(bin);
2251 //_____________________________________________________________________________
2252 Int_t AliAnalysisTaskPID::GetRandomParticleTypeAccordingToParticleFractions(Double_t trackPt, Double_t jetPt,
2253 Double_t centralityPercentile,
2254 Bool_t smearByError,
2255 Bool_t takeIntoAccountSysError) const
2257 // Uses the stored histograms with the particle fractions to generate a random particle type according to these fractions.
2258 // In case of problems (e.g. histo missing), AliPID::kUnknown is returned.
2259 // If smearByError is kTRUE, the used fractions will be random numbers distributed with a gauss with mean
2260 // being the corresponding particle fraction and sigma it's error.
2261 // Note that in this case only the fraction of a random species is varied in this way. The other fractions
2262 // will be re-normalised according their statistical errors.
2263 // The same holds for the systematic error of species "takeIntoAccountSpeciesSysError", but the random number will be
2264 // uniformly distributed within [mean - sys, mean + sys] and the re-normalisation will be weighted with the systematic errors.
2265 // Note that the fractions will be calculated first with only the systematic error taken into account (if desired), including
2266 // re-normalisation. Then, the resulting fractions will be used to calculate the final fractions - either with statistical error
2267 // or without. The species, for which the error will be used for smearing, is the same for sys and stat error.
2269 Double_t prob[AliPID::kSPECIES];
2270 Int_t randomSpecies = (smearByError || takeIntoAccountSysError) ? (Int_t)(fRandom->Rndm() * AliPID::kSPECIES) : -1;
2271 Bool_t success = GetParticleFractions(trackPt, jetPt, centralityPercentile, prob, randomSpecies, randomSpecies);
2274 return AliPID::kUnknown;
2276 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2278 if (rnd <= prob[AliPID::kPion])
2279 return AliPID::kPion;
2280 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon])
2281 return AliPID::kKaon;
2282 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton])
2283 return AliPID::kProton;
2284 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton] + prob[AliPID::kElectron])
2285 return AliPID::kElectron;
2287 return AliPID::kMuon; //else it must be a muon (only species left)
2291 //_____________________________________________________________________________
2292 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::GenerateDetectorResponse(AliAnalysisTaskPID::ErrorCode errCode,
2293 Double_t mean, Double_t sigma,
2294 Double_t* responses, Int_t nResponses,
2297 // Generate detector response. If a previous generation was not successful or there is something wrong with this signal generation,
2298 // the function will return kFALSE
2302 // Reset response array
2303 for (Int_t i = 0; i < nResponses; i++)
2304 responses[i] = -999;
2306 if (errCode == kError)
2309 ErrorCode ownErrCode = kNoErrors;
2311 if (fUseConvolutedGaus && !usePureGaus) {
2312 // In case of convoluted gauss, calculate the probability density only once to save a lot of time!
2314 TH1* hProbDensity = 0x0;
2315 ownErrCode = SetParamsForConvolutedGaus(mean, sigma);
2316 if (ownErrCode == kError)
2319 hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
2321 for (Int_t i = 0; i < nResponses; i++) {
2322 responses[i] = hProbDensity->GetRandom();
2323 //responses[i] fConvolutedGausDeltaPrime->GetRandom(); // MUCH slower than using the binned version via the histogram
2327 for (Int_t i = 0; i < nResponses; i++) {
2328 responses[i] = fRandom->Gaus(mean, sigma);
2332 // If forwarded error code was a warning (error case has been handled before), return a warning
2333 if (errCode == kWarning)
2336 return ownErrCode; // Forward success/warning
2340 //_____________________________________________________________________________
2341 void AliAnalysisTaskPID::PrintSettings(Bool_t printSystematicsSettings) const
2343 // Print current settings.
2345 printf("\n\nSettings for task %s:\n", GetName());
2346 printf("Is pPb/Pbp: %d -> %s\n", GetIsPbpOrpPb(), GetIsPbpOrpPb() ? "Adapting vertex cuts" : "Using standard vertex cuts");
2347 printf("Track cuts: %s\n", fTrackFilter ? fTrackFilter->GetTitle() : "-");
2348 printf("Eta cut: %.2f <= |eta| <= %.2f\n", GetEtaAbsCutLow(), GetEtaAbsCutUp());
2349 printf("Phi' cut: %d\n", GetUsePhiCut());
2350 printf("TPCCutMIGeo: %d\n", GetUseTPCCutMIGeo());
2351 if (GetUseTPCCutMIGeo()) {
2352 printf("GetCutGeo: %f\n", GetCutGeo());
2353 printf("GetCutNcr: %f\n", GetCutNcr());
2354 printf("GetCutNcl: %f\n", GetCutNcl());
2356 printf("TPCnclCut: %d\n", GetUseTPCnclCut());
2357 if (GetUseTPCnclCut()) {
2358 printf("GetCutPureNcl: %d\n", GetCutPureNcl());
2363 printf("Centrality estimator: %s\n", GetCentralityEstimator().Data());
2367 printf("Pile up rejection type: %d\n", (Int_t)fPileUpRejectionType);
2371 printf("Use MC-ID for signal generation: %d\n", GetUseMCidForGeneration());
2372 printf("Use ITS: %d\n", GetUseITS());
2373 printf("Use TOF: %d\n", GetUseTOF());
2374 printf("Use priors: %d\n", GetUsePriors());
2375 printf("Use TPC default priors: %d\n", GetUseTPCDefaultPriors());
2376 printf("Use convoluted Gauss: %d\n", GetUseConvolutedGaus());
2377 printf("Accuracy of non-Gaussian tail: %e\n", GetAccuracyNonGaussianTail());
2378 printf("Take into account muons: %d\n", GetTakeIntoAccountMuons());
2379 printf("TOF mode: %d\n", GetTOFmode());
2380 printf("\nParams for transition from gauss to asymmetric shape:\n");
2381 printf("[0]: %e\n", GetConvolutedGaussTransitionPar(0));
2382 printf("[1]: %e\n", GetConvolutedGaussTransitionPar(1));
2383 printf("[2]: %e\n", GetConvolutedGaussTransitionPar(2));
2387 printf("Do PID: %d\n", fDoPID);
2388 printf("Do Efficiency: %d\n", fDoEfficiency);
2389 printf("Do PtResolution: %d\n", fDoPtResolution);
2390 printf("Do dEdxCheck: %d\n", fDoDeDxCheck);
2391 printf("Do binZeroStudy: %d\n", fDoBinZeroStudy);
2395 printf("Input from other task: %d\n", GetInputFromOtherTask());
2396 printf("Store additional jet information: %d\n", GetStoreAdditionalJetInformation());
2397 printf("Store centrality percentile: %d", GetStoreCentralityPercentile());
2399 if (printSystematicsSettings)
2400 PrintSystematicsSettings();
2406 //_____________________________________________________________________________
2407 void AliAnalysisTaskPID::PrintSystematicsSettings() const
2409 // Print current settings for systematic studies.
2411 printf("\n\nSettings for systematics for task %s:\n", GetName());
2412 printf("SplinesThr:\t%f\n", GetSystematicScalingSplinesThreshold());
2413 printf("SplinesBelowThr:\t%f\n", GetSystematicScalingSplinesBelowThreshold());
2414 printf("SplinesAboveThr:\t%f\n", GetSystematicScalingSplinesAboveThreshold());
2415 printf("EtaCorrMomThr:\t%f\n", GetSystematicScalingEtaCorrectionMomentumThr());
2416 printf("EtaCorrLowP:\t%f\n", GetSystematicScalingEtaCorrectionLowMomenta());
2417 printf("EtaCorrHighP:\t%f\n", GetSystematicScalingEtaCorrectionHighMomenta());
2418 printf("SigmaParaThr:\t%f\n", GetSystematicScalingEtaSigmaParaThreshold());
2419 printf("SigmaParaBelowThr:\t%f\n", GetSystematicScalingEtaSigmaParaBelowThreshold());
2420 printf("SigmaParaAboveThr:\t%f\n", GetSystematicScalingEtaSigmaParaAboveThreshold());
2421 printf("MultCorr:\t%f\n", GetSystematicScalingMultCorrection());
2422 printf("TOF mode: %d\n", GetTOFmode());
2428 //_____________________________________________________________________________
2429 Bool_t AliAnalysisTaskPID::ProcessTrack(const AliVTrack* track, Int_t particlePDGcode, Double_t centralityPercentile,
2432 // Process the track (generate expected response, fill histos, etc.).
2433 // particlePDGcode == 0 means data. Otherwise, the corresponding MC ID will be assumed.
2435 //Printf("Debug: Task %s is starting to process track: dEdx %f, pTPC %f, eta %f, ncl %d\n", GetName(), track->GetTPCsignal(), track->GetTPCmomentum(),
2436 // track->Eta(), track->GetTPCsignalN());
2439 printf("File: %s, Line: %d: ProcessTrack\n", (char*)__FILE__, __LINE__);
2441 if (!fDoPID && !fDoDeDxCheck && !fDoPtResolution)
2445 printf("File: %s, Line: %d: ProcessTrack -> Processing started\n", (char*)__FILE__, __LINE__);
2447 const Bool_t isMC = (particlePDGcode == 0) ? kFALSE : kTRUE;
2452 if (TMath::Abs(particlePDGcode) == 211) {//Pion
2455 else if (TMath::Abs(particlePDGcode) == 321) {//Kaon
2458 else if (TMath::Abs(particlePDGcode) == 2212) {//Proton
2461 else if (TMath::Abs(particlePDGcode) == 11) {//Electron
2464 else if (TMath::Abs(particlePDGcode) == 13) {//Muon
2467 else // In MC-ID case, set to underflow bin such that the response from this track is only used for unidentified signal generation
2468 // or signal generation with PID response and the track is still there (as in data) - e.g. relevant w.r.t. deuterons.
2469 // This is important to be as much as possible consistent with data. And the tracks can still be removed by disabling the
2470 // underflow bin for the projections
2475 //Double_t p = track->GetP();
2476 const Double_t pTPC = track->GetTPCmomentum();
2477 Double_t pT = track->Pt();
2479 Double_t z = -1, xi = -1;
2480 GetJetTrackObservables(pT, jetPt, z, xi);
2483 Double_t trackCharge = track->Charge();
2486 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
2487 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
2488 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
2492 Printf("Skipping track with strange dEdx value: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), pTPC,
2493 track->Eta(), track->GetTPCsignalN());
2497 // Completely remove tracks from light nuclei defined by el and pr <dEdx> as function of pT.
2498 // A very loose cut to be sure not to throw away electrons and/or protons
2499 Double_t nSigmaPr = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kProton);
2500 Double_t nSigmaEl = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kElectron);
2502 if ((pTPC >= 0.3 && (nSigmaPr > 10 && nSigmaEl > 10)) ||
2503 (pTPC < 0.3 && (nSigmaPr > 15 && nSigmaEl > 15))) {
2505 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",
2506 track->GetTPCsignal(), pTPC, pT, track->Eta(), track->GetTPCsignalN(), nSigmaPr, nSigmaEl);
2511 Double_t dEdxEl, dEdxKa, dEdxPi, dEdxMu, dEdxPr;
2512 Double_t sigmaEl, sigmaKa, sigmaPi, sigmaMu, sigmaPr;
2514 if (fDoAnySystematicStudiesOnTheExpectedSignal) {
2515 // Get the uncorrected signal first and the corresponding correction factors.
2516 // Then modify the correction factors and properly recalculate the corrected dEdx
2518 // Get pure spline values for dEdx_expected, without any correction
2519 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2520 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2521 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2522 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2523 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2524 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2526 // Scale splines, if desired
2527 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
2528 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
2530 // Tune turn-on of correction for pions (not so relevant for the other species, since at very large momenta)
2532 Double_t scaleFactor = 1.;
2533 Double_t usedSystematicScalingSplines = 1.;
2535 bg = pTPC / AliPID::ParticleMass(AliPID::kElectron);
2536 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2537 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2538 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2539 dEdxEl *= usedSystematicScalingSplines;
2541 bg = pTPC / AliPID::ParticleMass(AliPID::kKaon);
2542 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2543 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2544 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2545 dEdxKa *= usedSystematicScalingSplines;
2547 bg = pTPC / AliPID::ParticleMass(AliPID::kPion);
2548 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2549 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2550 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2551 dEdxPi *= usedSystematicScalingSplines;
2553 if (fTakeIntoAccountMuons) {
2554 bg = pTPC / AliPID::ParticleMass(AliPID::kMuon);
2555 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2556 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2557 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2558 dEdxMu *= usedSystematicScalingSplines;
2562 bg = pTPC / AliPID::ParticleMass(AliPID::kProton);
2563 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2564 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2565 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2566 dEdxPr *= usedSystematicScalingSplines;
2569 // Get the eta correction factors for the (modified) expected dEdx
2570 Double_t etaCorrEl = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxEl) : 1.;
2571 Double_t etaCorrKa = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxKa) : 1.;
2572 Double_t etaCorrPi = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPi) : 1.;
2573 Double_t etaCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCEtaCorrection() ?
2574 fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxMu) : 1.;
2575 Double_t etaCorrPr = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPr) : 1.;
2577 // Scale eta correction factors, if desired (and eta correction maps are to be used, otherwise it is not possible!)
2578 if (fPIDResponse->UseTPCEtaCorrection() &&
2579 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon ||
2580 TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon)) {
2581 // Since we do not want to scale the splines with this, but only the eta variation, only scale the deviation of the correction factor!
2582 // 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!
2585 // Due to additional azimuthal effects, there is an additional eta dependence for low momenta which is not corrected successfully so far.
2586 // One can assign a different (higher) systematic scale factor for this low-p region and a threshold which separates low- and high-p.
2587 // 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
2588 Double_t usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionHighMomenta;
2590 if (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - fSystematicScalingEtaCorrectionLowMomenta) > fgkEpsilon) {
2591 const Double_t fractionHighMomentumScaleFactor = 0.5 * (1. + TMath::Erf((pTPC - fSystematicScalingEtaCorrectionMomentumThr) / 0.1));
2592 usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionLowMomenta * (1 - fractionHighMomentumScaleFactor)
2593 + fSystematicScalingEtaCorrectionHighMomenta * fractionHighMomentumScaleFactor;
2596 Double_t maxEtaVariationEl = GetMaxEtaVariation(dEdxEl);
2597 etaCorrEl = etaCorrEl * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrEl - 1.0) / maxEtaVariationEl);
2599 Double_t maxEtaVariationKa = GetMaxEtaVariation(dEdxKa);
2600 etaCorrKa = etaCorrKa * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrKa - 1.0) / maxEtaVariationKa);
2602 Double_t maxEtaVariationPi = GetMaxEtaVariation(dEdxPi);
2603 etaCorrPi = etaCorrPi * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPi - 1.0) / maxEtaVariationPi);
2605 if (fTakeIntoAccountMuons) {
2606 Double_t maxEtaVariationMu = GetMaxEtaVariation(dEdxMu);
2607 etaCorrMu = etaCorrMu * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrMu - 1.0) / maxEtaVariationMu);
2612 Double_t maxEtaVariationPr = GetMaxEtaVariation(dEdxPr);
2613 etaCorrPr = etaCorrPr * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPr - 1.0) / maxEtaVariationPr);
2617 etaCorrEl = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrEl - 1.0);
2618 etaCorrKa = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrKa - 1.0);
2619 etaCorrPi = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPi - 1.0);
2620 etaCorrMu = fTakeIntoAccountMuons ? (1.0 + usedSystematicScalingEtaCorrection * (etaCorrMu - 1.0)) : 1.0;
2621 etaCorrPr = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPr - 1.0);
2625 // Get the multiplicity correction factors for the (modified) expected dEdx
2626 const Int_t currEvtMultiplicity = fPIDResponse->GetTPCResponse().GetCurrentEventMultiplicity();
2628 Double_t multiplicityCorrEl = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2629 dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2630 Double_t multiplicityCorrKa = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2631 dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2632 Double_t multiplicityCorrPi = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2633 dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2634 Double_t multiplicityCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2635 fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track, dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2636 Double_t multiplicityCorrPr = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2637 dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2639 Double_t multiplicityCorrSigmaEl = fPIDResponse->UseTPCMultiplicityCorrection() ?
2640 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2641 Double_t multiplicityCorrSigmaKa = fPIDResponse->UseTPCMultiplicityCorrection() ?
2642 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2643 Double_t multiplicityCorrSigmaPi = fPIDResponse->UseTPCMultiplicityCorrection() ?
2644 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2645 Double_t multiplicityCorrSigmaMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2646 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2647 Double_t multiplicityCorrSigmaPr = fPIDResponse->UseTPCMultiplicityCorrection() ?
2648 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2650 // Scale multiplicity correction factors, if desired (and multiplicity correction functions are to be used, otherwise it is not possible!)
2651 if (fPIDResponse->UseTPCMultiplicityCorrection() && TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
2652 // Since we do not want to scale the splines with this, but only the multiplicity variation, only scale the deviation of the correction factor!
2653 // 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!
2655 multiplicityCorrEl = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrEl - 1.0);
2656 multiplicityCorrKa = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrKa - 1.0);
2657 multiplicityCorrPi = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPi - 1.0);
2658 multiplicityCorrMu = fTakeIntoAccountMuons ? (1.0 + fSystematicScalingMultCorrection * (multiplicityCorrMu - 1.0)) : 1.0;
2659 multiplicityCorrPr = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPr - 1.0);
2662 // eta correction must be enabled in order to use the new sigma parametrisation maps. Since this is the absolute sigma
2663 // for a track calculated with the unscaled paramaters, we have to devide out dEdxExpectedEtaCorrected and then need
2664 // to scale with the multiplicitySigmaCorrFactor * fSystematicScalingEtaSigmaPara. In the end, one has to scale with the
2665 // (modified) dEdx to get the absolute sigma
2666 // This means there is no extra parameter for the multiplicitySigmaCorrFactor, but only for the sigma map itself.
2667 // This is valid, since it appears only as a product. One has to assume a larger systematic shift in case of additional
2668 // multiplicity dependence....
2670 Bool_t doSigmaSystematics = (TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
2671 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon);
2674 Double_t dEdxElExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2676 Double_t systematicScalingEtaSigmaParaEl = 1.;
2677 if (doSigmaSystematics) {
2678 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxElExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2679 systematicScalingEtaSigmaParaEl = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2680 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2682 Double_t sigmaRelEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2684 / dEdxElExpected * systematicScalingEtaSigmaParaEl * multiplicityCorrSigmaEl;
2687 Double_t dEdxKaExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2689 Double_t systematicScalingEtaSigmaParaKa = 1.;
2690 if (doSigmaSystematics) {
2691 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxKaExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2692 systematicScalingEtaSigmaParaKa = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2693 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2695 Double_t sigmaRelKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2697 / dEdxKaExpected * systematicScalingEtaSigmaParaKa * multiplicityCorrSigmaKa;
2700 Double_t dEdxPiExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2702 Double_t systematicScalingEtaSigmaParaPi = 1.;
2703 if (doSigmaSystematics) {
2704 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPiExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2705 systematicScalingEtaSigmaParaPi = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2706 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2708 Double_t sigmaRelPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2710 / dEdxPiExpected * systematicScalingEtaSigmaParaPi * multiplicityCorrSigmaPi;
2713 Double_t sigmaRelMu = 999.;
2714 if (fTakeIntoAccountMuons) {
2715 Double_t dEdxMuExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2717 Double_t systematicScalingEtaSigmaParaMu = 1.;
2718 if (doSigmaSystematics) {
2719 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxMuExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2720 systematicScalingEtaSigmaParaMu = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2721 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2723 sigmaRelMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kTRUE, kFALSE)
2724 / dEdxMuExpected * systematicScalingEtaSigmaParaMu * multiplicityCorrSigmaMu;
2728 Double_t dEdxPrExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2730 Double_t systematicScalingEtaSigmaParaPr = 1.;
2731 if (doSigmaSystematics) {
2732 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPrExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2733 systematicScalingEtaSigmaParaPr = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2734 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2736 Double_t sigmaRelPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2738 / dEdxPrExpected * systematicScalingEtaSigmaParaPr * multiplicityCorrSigmaPr;
2740 // Now scale the (possibly modified) spline values with the (possibly modified) correction factors
2741 dEdxEl *= etaCorrEl * multiplicityCorrEl;
2742 dEdxKa *= etaCorrKa * multiplicityCorrKa;
2743 dEdxPi *= etaCorrPi * multiplicityCorrPi;
2744 dEdxMu *= etaCorrMu * multiplicityCorrMu;
2745 dEdxPr *= etaCorrPr * multiplicityCorrPr;
2747 // Finally, get the absolute sigma
2748 sigmaEl = sigmaRelEl * dEdxEl;
2749 sigmaKa = sigmaRelKa * dEdxKa;
2750 sigmaPi = sigmaRelPi * dEdxPi;
2751 sigmaMu = sigmaRelMu * dEdxMu;
2752 sigmaPr = sigmaRelPr * dEdxPr;
2756 // No systematic studies on expected signal - just take it as it comes from the TPCPIDResponse
2757 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2758 fPIDResponse->UseTPCEtaCorrection(),
2759 fPIDResponse->UseTPCMultiplicityCorrection());
2760 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2761 fPIDResponse->UseTPCEtaCorrection(),
2762 fPIDResponse->UseTPCMultiplicityCorrection());
2763 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2764 fPIDResponse->UseTPCEtaCorrection(),
2765 fPIDResponse->UseTPCMultiplicityCorrection());
2766 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2767 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2768 fPIDResponse->UseTPCEtaCorrection(),
2769 fPIDResponse->UseTPCMultiplicityCorrection());
2770 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2771 fPIDResponse->UseTPCEtaCorrection(),
2772 fPIDResponse->UseTPCMultiplicityCorrection());
2774 sigmaEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2775 fPIDResponse->UseTPCEtaCorrection(),
2776 fPIDResponse->UseTPCMultiplicityCorrection());
2777 sigmaKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2778 fPIDResponse->UseTPCEtaCorrection(),
2779 fPIDResponse->UseTPCMultiplicityCorrection());
2780 sigmaPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2781 fPIDResponse->UseTPCEtaCorrection(),
2782 fPIDResponse->UseTPCMultiplicityCorrection());
2783 sigmaMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2784 fPIDResponse->UseTPCEtaCorrection(),
2785 fPIDResponse->UseTPCMultiplicityCorrection());
2786 sigmaPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2787 fPIDResponse->UseTPCEtaCorrection(),
2788 fPIDResponse->UseTPCMultiplicityCorrection());
2791 Double_t deltaPrimeElectron = (dEdxEl > 0) ? dEdxTPC / dEdxEl : -1;
2793 Printf("Error: Expected TPC signal <= 0 for electron hypothesis");
2797 Double_t deltaPrimeKaon = (dEdxKa > 0) ? dEdxTPC / dEdxKa : -1;
2799 Printf("Error: Expected TPC signal <= 0 for kaon hypothesis");
2803 Double_t deltaPrimePion = (dEdxPi > 0) ? dEdxTPC / dEdxPi : -1;
2805 Printf("Error: Expected TPC signal <= 0 for pion hypothesis");
2809 Double_t deltaPrimeProton = (dEdxPr > 0) ? dEdxTPC / dEdxPr : -1;
2811 Printf("Error: Expected TPC signal <= 0 for proton hypothesis");
2816 printf("File: %s, Line: %d: ProcessTrack -> Compute probabilities\n", (char*)__FILE__, __LINE__);
2819 // Use probabilities to weigh the response generation for the different species.
2820 // Also determine the most probable particle type.
2821 Double_t prob[AliPID::kSPECIESC];
2822 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2825 fPIDcombined->ComputeProbabilities(track, fPIDResponse, prob);
2827 // If muons are not to be taken into account, just set their probability to zero and normalise the remaining probabilities later
2828 if (!fTakeIntoAccountMuons)
2829 prob[AliPID::kMuon] = 0;
2831 // Priors might cause problems in case of mismatches, i.e. mismatch particles will be identified as pions.
2832 // Can be easily caught for low p_TPC by just setting pion (and muon) probs to zero, if dEdx is larger than
2833 // expected dEdx of electrons and kaons
2834 if (pTPC < 1. && dEdxTPC > dEdxEl && dEdxTPC > dEdxKa) {
2835 prob[AliPID::kMuon] = 0;
2836 prob[AliPID::kPion] = 0;
2840 // Bug: One can set the number of species for PIDcombined, but PIDcombined will call PIDresponse, which writes without testing
2841 // the probs for kSPECIESC (including light nuclei) into the array.
2842 // In this case, when only kSPECIES are considered, the probabilities have to be rescaled!
2845 // 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
2846 // high-pT region (also contribution there completely negligable!)
2847 // 2. If dEdx is larger than the expected dEdx + 5 sigma of el and pr, it is most likely a light nucleus
2848 // (if dEdx is more than 5 sigma away from expectation, flat TPC probs are set... and the light nuclei splines are not
2851 // The highest expected dEdx is either for pr or for el. Assign 100% probability to the species with highest expected dEdx then.
2852 // In all other cases: Throw away light nuclei probs and rescale other probs to 100%.
2854 // Find most probable species for the ID
2855 Int_t maxIndex = TMath::LocMax(AliPID::kSPECIESC, prob);
2857 if ((prob[maxIndex] > 0 && maxIndex >= AliPID::kSPECIES && dEdxTPC > dEdxEl + 5. * sigmaEl) ||
2858 (dEdxTPC > dEdxEl + 5. * sigmaEl && dEdxTPC > dEdxPr + 5. * sigmaPr)) {
2859 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2862 if (dEdxEl > dEdxPr) {
2863 prob[AliPID::kElectron] = 1.;
2864 maxIndex = AliPID::kElectron;
2867 prob[AliPID::kProton] = 1.;
2868 maxIndex = AliPID::kProton;
2872 for (Int_t i = AliPID::kSPECIES; i < AliPID::kSPECIESC; i++)
2875 Double_t probSum = 0.;
2876 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2880 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2884 // If all probabilities are equal (should only happen if no priors are used), set most probable PID to pion
2885 // because LocMax returns just the first maximal value (i.e. AliPID::kElectron)
2886 if (TMath::Abs(prob[maxIndex] - 1. / AliPID::kSPECIES) < 1e-5)
2887 maxIndex = AliPID::kPion;
2889 // In all other cases, the maximum remains untouched from the scaling (and is < AliPID::kSPECIES by construction)
2893 // Generate the expected responses in DeltaPrime and translate to real dEdx. Only take responses for exactly that species
2894 // (i.e. with pre-PID)
2896 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
2898 ErrorCode errCode = kNoErrors;
2901 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check\n", (char*)__FILE__, __LINE__);
2904 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
2907 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
2910 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
2913 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
2915 if (errCode == kNoErrors) {
2916 Double_t genEntry[kDeDxCheckNumAxes];
2917 genEntry[kDeDxCheckJetPt] = jetPt;
2918 genEntry[kDeDxCheckEtaAbs] = TMath::Abs(track->Eta());
2919 genEntry[kDeDxCheckP] = pTPC;
2922 for (Int_t n = 0; n < numGenEntries; n++) {
2923 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
2924 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2926 // Consider generated response as originating from...
2927 if (rnd <= prob[AliPID::kElectron]) {
2928 genEntry[kDeDxCheckPID] = 0; // ... an electron
2929 genEntry[kDeDxCheckDeDx] = fGenRespElDeltaPrimeEl[n] * dEdxEl;
2931 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon]) {
2932 genEntry[kDeDxCheckPID] = 1; // ... a kaon
2933 genEntry[kDeDxCheckDeDx] = fGenRespKaDeltaPrimeKa[n] * dEdxKa;
2935 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion]) {
2936 genEntry[kDeDxCheckPID] = 2; // ... a pion (or a muon)
2937 genEntry[kDeDxCheckDeDx] = fGenRespPiDeltaPrimePi[n] * dEdxPi;
2940 genEntry[kDeDxCheckPID] = 3; // ... a proton
2941 genEntry[kDeDxCheckDeDx] = fGenRespPrDeltaPrimePr[n] * dEdxPr;
2944 fDeDxCheck->Fill(genEntry);
2949 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check done\n", (char*)__FILE__, __LINE__);
2952 if (fDoPtResolution) {
2953 // Check shared clusters, which is done together with the pT resolution
2954 Double_t qaEntry[kQASharedClsNumAxes];
2955 qaEntry[kQASharedClsJetPt] = jetPt;
2956 qaEntry[kQASharedClsPt] = pT;
2957 qaEntry[kDeDxCheckP] = pTPC;
2958 qaEntry[kQASharedClsNumSharedCls] = track->GetTPCSharedMapPtr()->CountBits();
2961 // iRowInd == -1 for "all rows w/o multiple counting"
2962 qaEntry[kQASharedClsPadRow] = iRowInd;
2963 fQASharedCls->Fill(qaEntry);
2965 // Fill hist for every pad row with shared cluster
2966 for (iRowInd = 0; iRowInd < 159; iRowInd++) {
2967 if (track->GetTPCSharedMapPtr()->TestBitNumber(iRowInd)) {
2968 qaEntry[kQASharedClsPadRow] = iRowInd;
2969 fQASharedCls->Fill(qaEntry);
2978 // Clean up the most probable PID for low momenta (not an issue for the probabilities, since fractions small,
2979 // but to get clean (and nice looking) templates (if most probable PID is used instead of generated responses), it should be done).
2980 // Problem: If more than 5 sigma away (and since priors also included), most probable PID for dEdx around protons could be pions.
2981 // Idea: Only clean selection for K and p possible. So, just take for the most probable PID the probs from TPC only calculated
2982 // by hand without restriction to 5 sigma and without priors. This will not affect the template generation, but afterwards one
2983 // can replace the K and p templates with the most probable PID distributions, so all other species templates remain the same.
2984 // I.e. it doesn't hurt if the most probable PID is distributed incorrectly between el, pi, mu.
2985 Bool_t maxIndexSetManually = kFALSE;
2988 Double_t probManualTPC[AliPID::kSPECIES];
2989 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2990 probManualTPC[i] = 0;
2992 probManualTPC[AliPID::kElectron] = TMath::Exp(-0.5*(dEdxTPC-dEdxEl)*(dEdxTPC-dEdxEl)/(sigmaEl*sigmaEl))/sigmaEl;
2993 // Muons are not important here, just ignore and save processing time
2994 probManualTPC[AliPID::kMuon] = 0.;//TMath::Exp(-0.5*(dEdxTPC-dEdxMu)*(dEdxTPC-dEdxMu)/(sigmaMu*sigmaMu))/sigmaMu;
2995 probManualTPC[AliPID::kPion] = TMath::Exp(-0.5*(dEdxTPC-dEdxPi)*(dEdxTPC-dEdxPi)/(sigmaPi*sigmaPi))/sigmaPi;
2996 probManualTPC[AliPID::kKaon] = TMath::Exp(-0.5*(dEdxTPC-dEdxKa)*(dEdxTPC-dEdxKa)/(sigmaKa*sigmaKa))/sigmaKa;
2997 probManualTPC[AliPID::kProton] = TMath::Exp(-0.5*(dEdxTPC-dEdxPr)*(dEdxTPC-dEdxPr)/(sigmaPr*sigmaPr))/sigmaPr;
2999 const Int_t maxIndexManualTPC = TMath::LocMax(AliPID::kSPECIES, probManualTPC);
3000 // Should always be > 0, but in case the dEdx is far off such that the machine accuracy sets every prob to zero,
3001 // better take the "old" result
3002 if (probManualTPC[maxIndexManualTPC] > 0.)
3003 maxIndex = maxIndexManualTPC;
3005 maxIndexSetManually = kTRUE;
3009 // Translate from AliPID numbering to numbering of this class
3010 if (prob[maxIndex] > 0 || maxIndexSetManually) {
3011 if (maxIndex == AliPID::kElectron)
3013 else if (maxIndex == AliPID::kKaon)
3015 else if (maxIndex == AliPID::kMuon)
3017 else if (maxIndex == AliPID::kPion)
3019 else if (maxIndex == AliPID::kProton)
3025 // Only take track into account for expectation values, if valid pid response is available.. Otherwise: Set to underflow bin.
3031 //For testing: Swap p<->pT to analyse pure p-dependence => Needs to be removed later
3037 TOFpidInfo tofPIDinfo = GetTOFType(track, fTOFmode);
3039 Double_t entry[fStoreAdditionalJetInformation ? kDataNumAxes : kDataNumAxes - fgkNumJetAxes];
3040 entry[kDataMCID] = binMC;
3041 entry[kDataSelectSpecies] = 0;
3042 entry[kDataPt] = pT;
3043 entry[kDataDeltaPrimeSpecies] = deltaPrimeElectron;
3044 entry[kDataCentrality] = centralityPercentile;
3046 if (fStoreAdditionalJetInformation) {
3047 entry[kDataJetPt] = jetPt;
3049 entry[kDataXi] = xi;
3052 entry[GetIndexOfChargeAxisData()] = trackCharge;
3053 entry[GetIndexOfTOFpidInfoAxisData()] = tofPIDinfo;
3055 fhPIDdataAll->Fill(entry);
3057 entry[kDataSelectSpecies] = 1;
3058 entry[kDataDeltaPrimeSpecies] = deltaPrimeKaon;
3059 fhPIDdataAll->Fill(entry);
3061 entry[kDataSelectSpecies] = 2;
3062 entry[kDataDeltaPrimeSpecies] = deltaPrimePion;
3063 fhPIDdataAll->Fill(entry);
3065 entry[kDataSelectSpecies] = 3;
3066 entry[kDataDeltaPrimeSpecies] = deltaPrimeProton;
3067 fhPIDdataAll->Fill(entry);
3070 // Construct the expected shape for the transition p -> pT
3072 Double_t genEntry[fStoreAdditionalJetInformation ? kGenNumAxes : kGenNumAxes - fgkNumJetAxes];
3073 genEntry[kGenMCID] = binMC;
3074 genEntry[kGenSelectSpecies] = 0;
3075 genEntry[kGenPt] = pT;
3076 genEntry[kGenDeltaPrimeSpecies] = -999;
3077 genEntry[kGenCentrality] = centralityPercentile;
3079 if (fStoreAdditionalJetInformation) {
3080 genEntry[kGenJetPt] = jetPt;
3081 genEntry[kGenZ] = z;
3082 genEntry[kGenXi] = xi;
3085 genEntry[GetIndexOfChargeAxisGen()] = trackCharge;
3086 genEntry[GetIndexOfTOFpidInfoAxisGen()] = tofPIDinfo;
3088 // Generate numGenEntries "responses" with fluctuations around the expected values.
3089 // fgkMaxNumGenEntries = 500 turned out to give reasonable templates even for highest track pT in 15-20 GeV/c jet pT bin.
3090 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
3092 /*OLD: Different number of responses depending on pT and jet pT for fgkMaxNumGenEntries = 1000
3093 * => Problem: If threshold to higher number of responses inside a bin (or after rebinning), then the template
3094 * is biased to the higher pT.
3095 // Generate numGenEntries "responses" with fluctuations around the expected values.
3096 // The higher the (transverse) momentum, the more "responses" will be generated in order not to run out of statistics too fast.
3097 Int_t numGenEntries = 10;
3099 // Jets have even worse statistics, therefore, scale numGenEntries further
3101 numGenEntries *= 20;
3102 else if (jetPt >= 20)
3103 numGenEntries *= 10;
3104 else if (jetPt >= 10)
3109 // Do not generate more entries than available in memory!
3110 if (numGenEntries > fgkMaxNumGenEntries)// fgkMaxNumGenEntries = 1000
3111 numGenEntries = fgkMaxNumGenEntries;
3115 ErrorCode errCode = kNoErrors;
3118 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses\n", (char*)__FILE__, __LINE__);
3121 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
3122 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxKa, sigmaEl / dEdxKa, fGenRespElDeltaPrimeKa, numGenEntries);
3123 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPi, sigmaEl / dEdxPi, fGenRespElDeltaPrimePi, numGenEntries);
3124 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPr, sigmaEl / dEdxPr, fGenRespElDeltaPrimePr, numGenEntries);
3127 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxEl, sigmaKa / dEdxEl, fGenRespKaDeltaPrimeEl, numGenEntries);
3128 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
3129 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPi, sigmaKa / dEdxPi, fGenRespKaDeltaPrimePi, numGenEntries);
3130 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPr, sigmaKa / dEdxPr, fGenRespKaDeltaPrimePr, numGenEntries);
3133 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxEl, sigmaPi / dEdxEl, fGenRespPiDeltaPrimeEl, numGenEntries);
3134 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxKa, sigmaPi / dEdxKa, fGenRespPiDeltaPrimeKa, numGenEntries);
3135 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
3136 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxPr, sigmaPi / dEdxPr, fGenRespPiDeltaPrimePr, numGenEntries);
3138 // Muons, if desired
3139 if (fTakeIntoAccountMuons) {
3140 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxEl, sigmaMu / dEdxEl, fGenRespMuDeltaPrimeEl, numGenEntries);
3141 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxKa, sigmaMu / dEdxKa, fGenRespMuDeltaPrimeKa, numGenEntries);
3142 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPi, sigmaMu / dEdxPi, fGenRespMuDeltaPrimePi, numGenEntries);
3143 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPr, sigmaMu / dEdxPr, fGenRespMuDeltaPrimePr, numGenEntries);
3147 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxEl, sigmaPr / dEdxEl, fGenRespPrDeltaPrimeEl, numGenEntries);
3148 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxKa, sigmaPr / dEdxKa, fGenRespPrDeltaPrimeKa, numGenEntries);
3149 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxPi, sigmaPr / dEdxPi, fGenRespPrDeltaPrimePi, numGenEntries);
3150 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
3152 if (errCode != kNoErrors) {
3153 if (errCode == kWarning && fDebug > 1) {
3154 Printf("Warning: Questionable detector response for track, most likely due to very low number of PID clusters! Debug output (dEdx_expected, sigma_expected):");
3157 Printf("Error: Failed to generate detector response for track - skipped! Debug output (dEdx_expected, sigma_expected):");
3160 Printf("Pr: %e, %e", dEdxPr, sigmaPr);
3161 Printf("Pi: %e, %e", dEdxPi, sigmaPi);
3162 Printf("El: %e, %e", dEdxEl, sigmaEl);
3163 Printf("Mu: %e, %e", dEdxMu, sigmaMu);
3164 Printf("Ka: %e, %e", dEdxKa, sigmaKa);
3165 Printf("track: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), track->GetTPCmomentum(), track->Eta(),
3166 track->GetTPCsignalN());
3169 if (errCode != kWarning) {
3170 return kFALSE;// Skip generated response in case of error
3174 for (Int_t n = 0; n < numGenEntries; n++) {
3175 if (!isMC || !fUseMCidForGeneration) {
3176 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
3177 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
3179 // Consider generated response as originating from...
3180 if (rnd <= prob[AliPID::kElectron])
3181 genEntry[kGenMCID] = 0; // ... an electron
3182 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon])
3183 genEntry[kGenMCID] = 1; // ... a kaon
3184 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon])
3185 genEntry[kGenMCID] = 2; // ... a muon -> NOTE: prob[AliPID::kMuon] = 0 in case of fTakeIntoAccountMuons = kFALSE
3186 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion])
3187 genEntry[kGenMCID] = 3; // ... a pion
3189 genEntry[kGenMCID] = 4; // ... a proton
3193 genEntry[kGenSelectSpecies] = 0;
3194 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeEl[n];
3195 fhGenEl->Fill(genEntry);
3197 genEntry[kGenSelectSpecies] = 1;
3198 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeKa[n];
3199 fhGenEl->Fill(genEntry);
3201 genEntry[kGenSelectSpecies] = 2;
3202 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePi[n];
3203 fhGenEl->Fill(genEntry);
3205 genEntry[kGenSelectSpecies] = 3;
3206 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePr[n];
3207 fhGenEl->Fill(genEntry);
3210 genEntry[kGenSelectSpecies] = 0;
3211 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeEl[n];
3212 fhGenKa->Fill(genEntry);
3214 genEntry[kGenSelectSpecies] = 1;
3215 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeKa[n];
3216 fhGenKa->Fill(genEntry);
3218 genEntry[kGenSelectSpecies] = 2;
3219 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePi[n];
3220 fhGenKa->Fill(genEntry);
3222 genEntry[kGenSelectSpecies] = 3;
3223 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePr[n];
3224 fhGenKa->Fill(genEntry);
3227 genEntry[kGenSelectSpecies] = 0;
3228 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeEl[n];
3229 fhGenPi->Fill(genEntry);
3231 genEntry[kGenSelectSpecies] = 1;
3232 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeKa[n];
3233 fhGenPi->Fill(genEntry);
3235 genEntry[kGenSelectSpecies] = 2;
3236 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePi[n];
3237 fhGenPi->Fill(genEntry);
3239 genEntry[kGenSelectSpecies] = 3;
3240 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePr[n];
3241 fhGenPi->Fill(genEntry);
3243 if (fTakeIntoAccountMuons) {
3244 // Muons, if desired
3245 genEntry[kGenSelectSpecies] = 0;
3246 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeEl[n];
3247 fhGenMu->Fill(genEntry);
3249 genEntry[kGenSelectSpecies] = 1;
3250 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeKa[n];
3251 fhGenMu->Fill(genEntry);
3253 genEntry[kGenSelectSpecies] = 2;
3254 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePi[n];
3255 fhGenMu->Fill(genEntry);
3257 genEntry[kGenSelectSpecies] = 3;
3258 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePr[n];
3259 fhGenMu->Fill(genEntry);
3263 genEntry[kGenSelectSpecies] = 0;
3264 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeEl[n];
3265 fhGenPr->Fill(genEntry);
3267 genEntry[kGenSelectSpecies] = 1;
3268 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeKa[n];
3269 fhGenPr->Fill(genEntry);
3271 genEntry[kGenSelectSpecies] = 2;
3272 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePi[n];
3273 fhGenPr->Fill(genEntry);
3275 genEntry[kGenSelectSpecies] = 3;
3276 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePr[n];
3277 fhGenPr->Fill(genEntry);
3281 printf("File: %s, Line: %d: ProcessTrack -> Done\n", (char*)__FILE__, __LINE__);
3287 //_____________________________________________________________________________
3288 Bool_t AliAnalysisTaskPID::SetConvolutedGaussLambdaParameter(Double_t lambda)
3290 // Set the lambda parameter of the convolution to the desired value. Automatically
3291 // calculates the parameters for the transition (restricted) gauss -> convoluted gauss.
3292 fConvolutedGaussTransitionPars[2] = lambda;
3294 // Save old parameters and settings of function to restore them later:
3295 Double_t* oldFuncParams = new Double_t[fkConvolutedGausNPar];
3296 for (Int_t i = 0; i < fkConvolutedGausNPar; i++)
3297 oldFuncParams[i] = fConvolutedGausDeltaPrime->GetParameter(i);
3298 Int_t oldFuncNpx = fConvolutedGausDeltaPrime->GetNpx();
3299 Double_t oldFuncRangeLow = 0, oldFuncRangeUp = 100;
3300 fConvolutedGausDeltaPrime->GetRange(oldFuncRangeLow, oldFuncRangeUp);
3302 // Choose some sufficiently large range
3303 const Double_t rangeStart = 0.5;
3304 const Double_t rangeEnd = 2.0;
3306 // To get the parameters for the transition, just choose arbitrarily input parameters for mu and sigma
3307 // (it makes sense to choose typical values). The ratio sigma_gauss / sigma_convolution is independent
3308 // of mu and as well the difference mu_gauss - mu_convolution.
3309 Double_t muInput = 1.0;
3310 Double_t sigmaInput = fgkSigmaReferenceForTransitionPars;
3313 // Step 1: Generate distribution with input parameters
3314 const Int_t nPar = 3;
3315 Double_t inputPar[nPar] = { muInput, sigmaInput, lambda };
3317 TH1D* hInput = new TH1D("hInput", "Input distribution", 2000, rangeStart, rangeEnd);
3319 fConvolutedGausDeltaPrime->SetParameters(inputPar);
3320 fConvolutedGausDeltaPrime->SetRange(rangeStart, rangeEnd);
3321 fConvolutedGausDeltaPrime->SetNpx(2000);
3324 // The resolution and mean of the AliPIDResponse are determined in finite intervals
3325 // of ncl (also second order effects due to finite dEdx and tanTheta).
3326 // Take this into account for the transition parameters via assuming an approximately flat
3327 // distritubtion in ncl in this interval.
3328 // NOTE: The ncl interval should be the same as the one used for the sigma map creation!
3329 const Int_t nclStart = 151;
3330 const Int_t nclEnd = 160;
3331 const Int_t nclSteps = (nclEnd - nclStart) + 1;
3332 for (Int_t ncl = nclStart; ncl <= nclEnd; ncl++) {
3333 // Resolution scales with 1/sqrt(ncl)
3334 fConvolutedGausDeltaPrime->SetParameter(1, inputPar[1] * sqrt(nclEnd) / sqrt(ncl));
3335 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3337 for (Int_t i = 0; i < 50000000 / nclSteps; i++)
3338 hInput->Fill(hProbDensity->GetRandom());
3342 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3344 for (Int_t i = 0; i < 50000000; i++)
3345 hInput->Fill(hProbDensity->GetRandom());
3347 // Step 2: Fit generated distribution with restricted gaussian
3348 Int_t maxBin = hInput->GetMaximumBin();
3349 Double_t max = hInput->GetBinContent(maxBin);
3351 UChar_t usedBins = 1;
3353 max += hInput->GetBinContent(maxBin - 1);
3356 if (maxBin < hInput->GetNbinsX()) {
3357 max += hInput->GetBinContent(maxBin + 1);
3362 // NOTE: The range (<-> fraction of maximum) should be the same
3363 // as for the spline and eta maps creation
3364 const Double_t lowThreshold = hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max));
3365 const Double_t highThreshold = hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max));
3367 TFitResultPtr fitResGaussFirstStep = hInput->Fit("gaus", "QNRS", "", lowThreshold, highThreshold);
3369 TFitResultPtr fitResGauss;
3371 if ((Int_t)fitResGaussFirstStep == 0) {
3372 TF1 fGauss("fGauss", "[0]*TMath::Gaus(x, [1], [2], 1)", rangeStart, rangeEnd);
3373 fGauss.SetParameter(0, fitResGaussFirstStep->GetParams()[0]);
3374 fGauss.SetParError(0, fitResGaussFirstStep->GetErrors()[0]);
3375 fGauss.SetParameter(2, fitResGaussFirstStep->GetParams()[2]);
3376 fGauss.SetParError(2, fitResGaussFirstStep->GetErrors()[2]);
3378 fGauss.FixParameter(1, fitResGaussFirstStep->GetParams()[1]);
3379 fitResGauss = hInput->Fit(&fGauss, "QNS", "s", rangeStart, rangeEnd);
3382 fitResGauss = hInput->Fit("gaus", "QNRS", "same", rangeStart, rangeEnd);
3384 //OLD TFitResultPtr fitResGauss = hInput->Fit("gaus", "QNRS", "", hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max)),
3385 // hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max)));
3388 // Step 3: Use parameters from gaussian fit to obtain parameters for the transition "restricted gauss" -> "convoluted gauss"
3390 // 3.1 The ratio sigmaInput / sigma_gaussFit ONLY depends on lambda (which is fixed per period) -> Calculate this first
3391 // for an arbitrary (here: typical) sigma. The ratio is then ~the same for ALL sigma for given lambda!
3392 if ((Int_t)fitResGauss != 0) {
3393 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Gauss Fit failed!\n");
3394 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3395 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3396 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3399 delete [] oldFuncParams;
3404 if (fitResGauss->GetParams()[2] <= 0) {
3405 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Sigma of gauss fit <= 0!\n");
3406 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3407 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3408 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3411 delete [] oldFuncParams;
3416 // sigma correction factor
3417 fConvolutedGaussTransitionPars[1] = sigmaInput / fitResGauss->GetParams()[2];
3419 // 3.2 Now that sigma und lambda are determined, one can calculate mu by shifting the maximum to the desired position,
3420 // i.e. the maximum of the input distribution should coincide with that of the re-calculated distribution,
3421 // which is achieved by getting the same mu for the same sigma.
3422 // NOTE: For fixed lambda, the shift is proportional to sigma and independent of mu!
3423 // So, one can calculate the shift for an arbitrary fixed (here: typical)
3424 // sigma and then simply use this shift for any other sigma by scaling it correspondingly!!!
3426 // Mu shift correction:
3427 // Shift in mu (difference between mean of gauss and mean of convolution) is proportional to sigma!
3428 // Thus, choose a reference sigma (typical -> 0.05), such that for arbitrary sigma one can simple scale
3429 // this shift correction with sigma / referenceSigma.
3430 fConvolutedGaussTransitionPars[0] = (fitResGauss->GetParams()[1] - muInput);
3433 /*Changed on 03.07.2013
3435 // Maximum of fConvolutedGausDeltaPrime should agree with maximum of input
3436 Double_t par[nPar] = { fitResGauss->GetParams()[1], // just as a guess of the maximum position
3440 fConvolutedGausDeltaPrime->SetParameters(par);
3442 Double_t maxXInput = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, muInput - 3. * sigmaInput),
3443 muInput + 10. * sigmaInput,
3446 // Maximum shifts proportional to sigma and is linear in mu (~mean of gauss)
3447 // Maximum should be typically located within [gaussMean, gaussMean + 3 gaussSigma].
3448 // -> Larger search range for safety reasons (also: sigma and/or mean might be not 100% accurate).
3449 Double_t maxXconvoluted = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001,
3450 fitResGauss->GetParams()[1] - 3. * fitResGauss->GetParams()[2]),
3451 fitResGauss->GetParams()[1] + 10. * fitResGauss->GetParams()[2],
3453 if (maxXconvoluted <= 0) {
3454 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Maximum of fConvolutedGausDeltaPrime <= 0!\n");
3456 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3457 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3458 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3461 delete [] oldFuncParams;
3466 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX to input value.
3467 // Mu shift correction:
3468 fConvolutedGaussTransitionPars[0] = maxXconvoluted - maxXInput;
3473 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3474 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3475 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3478 delete [] oldFuncParams;
3484 //_____________________________________________________________________________
3485 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::SetParamsForConvolutedGaus(Double_t gausMean, Double_t gausSigma)
3487 // Set parameters for convoluted gauss using parameters for a pure gaussian.
3488 // If SetConvolutedGaussLambdaParameter has not been called before to initialise the translation parameters,
3489 // some default parameters will be used and an error will show up.
3492 printf("File: %s, Line: %d: SetParamsForConvolutedGaus: mean %e, sigma %e\n", (char*)__FILE__, __LINE__, gausMean, gausSigma);
3494 if (fConvolutedGaussTransitionPars[1] < -998) {
3495 AliError("Transition parameters not initialised! Default parameters will be used. Please call SetConvolutedGaussLambdaParameter(...) before any calculations!");
3496 SetConvolutedGaussLambdaParameter(2.0);
3497 AliError(Form("Parameters set to:\n[0]: %f\n[1]: %f\n[2]: %f\n", fConvolutedGaussTransitionPars[0],
3498 fConvolutedGaussTransitionPars[1], fConvolutedGaussTransitionPars[2]));
3501 Double_t par[fkConvolutedGausNPar];
3502 par[2] = fConvolutedGaussTransitionPars[2];
3503 par[1] = fConvolutedGaussTransitionPars[1] * gausSigma;
3504 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX so that it sits at the right place.
3505 par[0] = gausMean - fConvolutedGaussTransitionPars[0] * par[1] / fgkSigmaReferenceForTransitionPars;
3507 ErrorCode errCode = kNoErrors;
3508 fConvolutedGausDeltaPrime->SetParameters(par);
3511 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> Parameters set to: %e, %e, %e (transition pars: %e, %e, %e, %e)\n",
3512 (char*)__FILE__, __LINE__, par[0], par[1], par[2], fConvolutedGaussTransitionPars[0], fConvolutedGaussTransitionPars[1],
3513 fConvolutedGaussTransitionPars[2], fgkSigmaReferenceForTransitionPars);
3515 fConvolutedGausDeltaPrime->SetNpx(20); // Small value speeds up following algorithm (valid, since extrema far apart)
3517 // Accuracy of 10^-5 is enough to get 0.1% precise peak for MIPS w.r.t. to dEdx = 2000 of protons
3518 // (should boost up the algorithm, because 10^-10 is the default value!)
3519 Double_t maxX= fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, gausMean - 2. * gausSigma),
3520 gausMean + 6. * gausSigma, 1.0E-5);
3522 const Double_t maximum = fConvolutedGausDeltaPrime->Eval(maxX);
3523 const Double_t maximumFraction = maximum * fAccuracyNonGaussianTail;
3525 // Estimate lower boundary for subsequent search:
3526 Double_t lowBoundSearchBoundLow = TMath::Max(1e-4, maxX - 5. * gausSigma);
3527 Double_t lowBoundSearchBoundUp = maxX;
3529 Bool_t lowerBoundaryFixedAtZero = kFALSE;
3531 while (fConvolutedGausDeltaPrime->Eval(lowBoundSearchBoundLow) >= maximumFraction) {
3532 if (lowBoundSearchBoundLow <= 0) {
3533 // This should only happen to low dEdx particles with very few clusters and therefore large sigma, such that the gauss goes below zero deltaPrime
3534 if (maximum <= 0) { // Something is weired
3535 printf("Error generating signal: maximum is <= 0!\n");
3539 const Double_t valueAtZero = fConvolutedGausDeltaPrime->Eval(0);
3540 if (valueAtZero / maximum > 0.05) {
3541 // Too large fraction below zero deltaPrime. Signal generation cannot be reliable in this case
3542 printf("Error generating signal: Too large fraction below zero deltaPrime: convGauss(0) / convGauss(max) = %e / %e = %e!\n",
3543 valueAtZero, maximum, valueAtZero / maximum);
3549 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",
3550 fConvolutedGausDeltaPrime->Eval(maxX), fAccuracyNonGaussianTail, maximumFraction, maxX, par[0], par[1], par[2], gausMean, gausSigma);
3553 lowerBoundaryFixedAtZero = kTRUE;
3555 if (errCode != kError)
3561 lowBoundSearchBoundUp -= gausSigma;
3562 lowBoundSearchBoundLow -= gausSigma;
3564 if (lowBoundSearchBoundLow < 0) {
3565 lowBoundSearchBoundLow = 0;
3566 lowBoundSearchBoundUp += gausSigma;
3570 // Determine lower boundary inside estimated range. For small values of the maximum: Need more precision, since finer binning!
3571 Double_t rangeStart = lowerBoundaryFixedAtZero ? 0 :
3572 fConvolutedGausDeltaPrime->GetX(maximumFraction, lowBoundSearchBoundLow, lowBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3574 // .. and the same for the upper boundary
3575 Double_t rangeEnd = 0;
3576 // If distribution starts beyond upper boundary, everything ends up in the overflow bin. So, just reduce range and Npx to minimum
3577 if (rangeStart > fkDeltaPrimeUpLimit) {
3578 rangeEnd = rangeStart + 0.00001;
3579 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3580 fConvolutedGausDeltaPrime->SetNpx(4);
3583 // Estimate upper boundary for subsequent search:
3584 Double_t upBoundSearchBoundUp = maxX + 5 * gausSigma;
3585 Double_t upBoundSearchBoundLow = maxX;
3586 while (fConvolutedGausDeltaPrime->Eval(upBoundSearchBoundUp) >= maximumFraction) {
3587 upBoundSearchBoundUp += gausSigma;
3588 upBoundSearchBoundLow += gausSigma;
3591 // For small values of the maximum: Need more precision, since finer binning!
3592 rangeEnd = fConvolutedGausDeltaPrime->GetX(maximumFraction, upBoundSearchBoundLow, upBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3594 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3595 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3597 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3598 //fConvolutedGausDeltaPrime->SetNpx(fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeEnd)
3599 // - fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeStart) + 1);
3600 //fConvolutedGausDeltaPrime->SetNpx((rangeEnd - rangeStart) / fDeltaPrimeBinWidth + 1);
3604 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> range %f - %f, error code %d\n", (char*)__FILE__, __LINE__,
3605 rangeStart, rangeEnd, errCode);
3611 //________________________________________________________________________
3612 void AliAnalysisTaskPID::SetUpGenHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3614 // Sets bin limits for axes which are not standard binned and the axes titles.
3616 hist->SetBinEdges(kGenPt, binsPt);
3617 hist->SetBinEdges(kGenDeltaPrimeSpecies, binsDeltaPrime);
3618 hist->SetBinEdges(kGenCentrality, binsCent);
3620 if (fStoreAdditionalJetInformation)
3621 hist->SetBinEdges(kGenJetPt, binsJetPt);
3624 hist->GetAxis(kGenMCID)->SetTitle("MC PID");
3625 hist->GetAxis(kGenMCID)->SetBinLabel(1, "e");
3626 hist->GetAxis(kGenMCID)->SetBinLabel(2, "K");
3627 hist->GetAxis(kGenMCID)->SetBinLabel(3, "#mu");
3628 hist->GetAxis(kGenMCID)->SetBinLabel(4, "#pi");
3629 hist->GetAxis(kGenMCID)->SetBinLabel(5, "p");
3631 hist->GetAxis(kGenSelectSpecies)->SetTitle("Select Species");
3632 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(1, "e");
3633 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(2, "K");
3634 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(3, "#pi");
3635 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(4, "p");
3637 hist->GetAxis(kGenPt)->SetTitle("p_{T} (GeV/c)");
3639 hist->GetAxis(kGenDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3641 hist->GetAxis(kGenCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3643 if (fStoreAdditionalJetInformation) {
3644 hist->GetAxis(kGenJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3646 hist->GetAxis(kGenZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3648 hist->GetAxis(kGenXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3651 hist->GetAxis(GetIndexOfChargeAxisGen())->SetTitle("Charge (e_{0})");
3653 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetTitle("TOF PID Info");
3654 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3655 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3656 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3657 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3658 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3659 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3663 //________________________________________________________________________
3664 void AliAnalysisTaskPID::SetUpGenYieldHist(THnSparse* hist, Double_t* binsPt, Double_t* binsCent, Double_t* binsJetPt) const
3666 // Sets bin limits for axes which are not standard binned and the axes titles.
3668 hist->SetBinEdges(kGenYieldPt, binsPt);
3669 hist->SetBinEdges(kGenYieldCentrality, binsCent);
3670 if (fStoreAdditionalJetInformation)
3671 hist->SetBinEdges(kGenYieldJetPt, binsJetPt);
3673 for (Int_t i = 0; i < 5; i++)
3674 hist->GetAxis(kGenYieldMCID)->SetBinLabel(i + 1, AliPID::ParticleLatexName(i));
3677 hist->GetAxis(kGenYieldMCID)->SetTitle("MC PID");
3678 hist->GetAxis(kGenYieldPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3679 hist->GetAxis(kGenYieldCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3681 if (fStoreAdditionalJetInformation) {
3682 hist->GetAxis(kGenYieldJetPt)->SetTitle("p_{T}^{jet, gen} (GeV/c)");
3684 hist->GetAxis(kGenYieldZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3686 hist->GetAxis(kGenYieldXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3689 hist->GetAxis(GetIndexOfChargeAxisGenYield())->SetTitle("Charge (e_{0})");
3693 //________________________________________________________________________
3694 void AliAnalysisTaskPID::SetUpHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3696 // Sets bin limits for axes which are not standard binned and the axes titles.
3698 hist->SetBinEdges(kDataPt, binsPt);
3699 hist->SetBinEdges(kDataDeltaPrimeSpecies, binsDeltaPrime);
3700 hist->SetBinEdges(kDataCentrality, binsCent);
3702 if (fStoreAdditionalJetInformation)
3703 hist->SetBinEdges(kDataJetPt, binsJetPt);
3706 hist->GetAxis(kDataMCID)->SetTitle("MC PID");
3707 hist->GetAxis(kDataMCID)->SetBinLabel(1, "e");
3708 hist->GetAxis(kDataMCID)->SetBinLabel(2, "K");
3709 hist->GetAxis(kDataMCID)->SetBinLabel(3, "#mu");
3710 hist->GetAxis(kDataMCID)->SetBinLabel(4, "#pi");
3711 hist->GetAxis(kDataMCID)->SetBinLabel(5, "p");
3713 hist->GetAxis(kDataSelectSpecies)->SetTitle("Select Species");
3714 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(1, "e");
3715 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(2, "K");
3716 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(3, "#pi");
3717 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(4, "p");
3719 hist->GetAxis(kDataPt)->SetTitle("p_{T} (GeV/c)");
3721 hist->GetAxis(kDataDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3723 hist->GetAxis(kDataCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3725 if (fStoreAdditionalJetInformation) {
3726 hist->GetAxis(kDataJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3728 hist->GetAxis(kDataZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3730 hist->GetAxis(kDataXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3733 hist->GetAxis(GetIndexOfChargeAxisData())->SetTitle("Charge (e_{0})");
3735 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetTitle("TOF PID Info");
3736 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3737 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3738 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3739 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3740 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3741 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3745 //________________________________________________________________________
3746 void AliAnalysisTaskPID::SetUpPtResHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt, Double_t* binsCent) const
3748 // Sets bin limits for axes which are not standard binned and the axes titles.
3750 hist->SetBinEdges(kPtResJetPt, binsJetPt);
3751 hist->SetBinEdges(kPtResGenPt, binsPt);
3752 hist->SetBinEdges(kPtResRecPt, binsPt);
3753 hist->SetBinEdges(kPtResCentrality, binsCent);
3756 hist->GetAxis(kPtResJetPt)->SetTitle("p_{T}^{jet, rec} (GeV/c)");
3757 hist->GetAxis(kPtResGenPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3758 hist->GetAxis(kPtResRecPt)->SetTitle("p_{T}^{rec} (GeV/c)");
3760 hist->GetAxis(kPtResCharge)->SetTitle("Charge (e_{0})");
3761 hist->GetAxis(kPtResCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3765 //________________________________________________________________________
3766 void AliAnalysisTaskPID::SetUpSharedClsHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt) const
3768 // Sets bin limits for axes which are not standard binned and the axes titles.
3770 hist->SetBinEdges(kQASharedClsJetPt, binsJetPt);
3771 hist->SetBinEdges(kQASharedClsPt, binsPt);
3774 hist->GetAxis(kQASharedClsJetPt)->SetTitle("#it{p}_{T}^{jet} (GeV/#it{c})");
3775 hist->GetAxis(kQASharedClsPt)->SetTitle("#it{p}_{T} (GeV/#it{c})");
3776 hist->GetAxis(kQASharedClsNumSharedCls)->SetTitle("#it{N}_{shared}^{cls}");
3777 hist->GetAxis(kQASharedClsPadRow)->SetTitle("Pad row");
3782 //________________________________________________________________________
3783 void AliAnalysisTaskPID::SetUpDeDxCheckHist(THnSparse* hist, const Double_t* binsPt, const Double_t* binsJetPt, const Double_t* binsEtaAbs) const
3785 // Sets bin limits for axes which are not standard binned and the axes titles.
3786 hist->SetBinEdges(kDeDxCheckP, binsPt);
3787 hist->SetBinEdges(kDeDxCheckJetPt, binsJetPt);
3788 hist->SetBinEdges(kDeDxCheckEtaAbs, binsEtaAbs);
3792 hist->GetAxis(kDeDxCheckPID)->SetTitle("PID");
3793 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(1, "e");
3794 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(2, "K");
3795 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(3, "#pi");
3796 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(4, "p");
3799 hist->GetAxis(kDeDxCheckJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3800 hist->GetAxis(kDeDxCheckEtaAbs)->SetTitle("|#eta|");
3801 hist->GetAxis(kDeDxCheckP)->SetTitle("p_{TPC} (GeV/c)");
3802 hist->GetAxis(kDeDxCheckDeDx)->SetTitle("TPC dE/dx (arb. unit)");
3806 //________________________________________________________________________
3807 void AliAnalysisTaskPID::SetUpBinZeroStudyHist(THnSparse* hist, const Double_t* binsCent, const Double_t* binsPt) const
3809 // Sets bin limits for axes which are not standard binned and the axes titles.
3810 hist->SetBinEdges(kBinZeroStudyCentrality, binsCent);
3811 hist->SetBinEdges(kBinZeroStudyGenPt, binsPt);
3814 hist->GetAxis(kBinZeroStudyCentrality)->SetTitle(Form("Centrality Percentile (%s)", GetPPCentralityEstimator().Data()));
3815 hist->GetAxis(kBinZeroStudyGenEta)->SetTitle("#it{#eta}^{gen}");
3816 hist->GetAxis(kBinZeroStudyGenPt)->SetTitle("#it{p}_{T}^{gen} (GeV/#it{c})");