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(kTRUE)
58 , fStoreCentralityPercentile(kFALSE)
59 , fStoreAdditionalJetInformation(kFALSE)
60 , fTakeIntoAccountMuons(kFALSE)
64 , fTPCDefaultPriors(kFALSE)
65 , fUseMCidForGeneration(kTRUE)
66 , fUseConvolutedGaus(kFALSE)
67 , fkConvolutedGausNPar(3)
68 , fAccuracyNonGaussianTail(1e-8)
69 , fkDeltaPrimeLowLimit(0.02)
70 , fkDeltaPrimeUpLimit(40.0)
71 , fConvolutedGausDeltaPrime(0x0)
75 , fPileUpRejectionType(AliAnalysisTaskPIDV0base::kPileUpRejectionOff)
76 , fDoAnySystematicStudiesOnTheExpectedSignal(kFALSE)
77 , fSystematicScalingSplinesThreshold(50.)
78 , fSystematicScalingSplinesBelowThreshold(1.0)
79 , fSystematicScalingSplinesAboveThreshold(1.0)
80 , fSystematicScalingEtaCorrectionMomentumThr(0.35)
81 , fSystematicScalingEtaCorrectionLowMomenta(1.0)
82 , fSystematicScalingEtaCorrectionHighMomenta(1.0)
83 , fSystematicScalingEtaSigmaParaThreshold(250.)
84 , fSystematicScalingEtaSigmaParaBelowThreshold(1.0)
85 , fSystematicScalingEtaSigmaParaAboveThreshold(1.0)
86 , fSystematicScalingMultCorrection(1.0)
87 , fCentralityEstimator("V0M")
94 , fGenRespElDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
95 , fGenRespElDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
96 , fGenRespElDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
97 , fGenRespElDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
98 , fGenRespKaDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
99 , fGenRespKaDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
100 , fGenRespKaDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
101 , fGenRespKaDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
102 , fGenRespPiDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
103 , fGenRespPiDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
104 , fGenRespPiDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
105 , fGenRespPiDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
106 , fGenRespMuDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
107 , fGenRespMuDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
108 , fGenRespMuDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
109 , fGenRespMuDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
110 , fGenRespPrDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
111 , fGenRespPrDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
112 , fGenRespPrDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
113 , fGenRespPrDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
115 , fGenRespElDeltaEl(new Double_t[fgkMaxNumGenEntries])
116 , fGenRespElDeltaKa(new Double_t[fgkMaxNumGenEntries])
117 , fGenRespElDeltaPi(new Double_t[fgkMaxNumGenEntries])
118 , fGenRespElDeltaPr(new Double_t[fgkMaxNumGenEntries])
119 , fGenRespKaDeltaEl(new Double_t[fgkMaxNumGenEntries])
120 , fGenRespKaDeltaKa(new Double_t[fgkMaxNumGenEntries])
121 , fGenRespKaDeltaPi(new Double_t[fgkMaxNumGenEntries])
122 , fGenRespKaDeltaPr(new Double_t[fgkMaxNumGenEntries])
123 , fGenRespPiDeltaEl(new Double_t[fgkMaxNumGenEntries])
124 , fGenRespPiDeltaKa(new Double_t[fgkMaxNumGenEntries])
125 , fGenRespPiDeltaPi(new Double_t[fgkMaxNumGenEntries])
126 , fGenRespPiDeltaPr(new Double_t[fgkMaxNumGenEntries])
127 , fGenRespMuDeltaEl(new Double_t[fgkMaxNumGenEntries])
128 , fGenRespMuDeltaKa(new Double_t[fgkMaxNumGenEntries])
129 , fGenRespMuDeltaPi(new Double_t[fgkMaxNumGenEntries])
130 , fGenRespMuDeltaPr(new Double_t[fgkMaxNumGenEntries])
131 , fGenRespPrDeltaEl(new Double_t[fgkMaxNumGenEntries])
132 , fGenRespPrDeltaKa(new Double_t[fgkMaxNumGenEntries])
133 , fGenRespPrDeltaPi(new Double_t[fgkMaxNumGenEntries])
134 , fGenRespPrDeltaPr(new Double_t[fgkMaxNumGenEntries])
136 , fDeltaPrimeAxis(0x0)
137 , fhMaxEtaVariation(0x0)
138 , fhEventsProcessed(0x0)
139 , fhEventsTriggerSel(0x0)
140 , fhEventsTriggerSelVtxCut(0x0)
141 , fhEventsProcessedNoPileUpRejection(0x0)
142 , fhMCgeneratedYieldsPrimaries(0x0)
150 , fOutputContainer(0x0)
153 // default Constructor
155 AliLog::SetClassDebugLevel("AliAnalysisTaskPID", AliLog::kInfo);
157 fConvolutedGausDeltaPrime = new TF1("convolutedGausDeltaPrime", this, &AliAnalysisTaskPID::ConvolutedGaus,
158 fkDeltaPrimeLowLimit, fkDeltaPrimeUpLimit,
159 fkConvolutedGausNPar, "AliAnalysisTaskPID", "ConvolutedGaus");
161 // Set some arbitrary parameteres, such that the function call will not crash
162 // (although it should not be called with these parameters...)
163 fConvolutedGausDeltaPrime->SetParameter(0, 0);
164 fConvolutedGausDeltaPrime->SetParameter(1, 1);
165 fConvolutedGausDeltaPrime->SetParameter(2, 2);
168 // Initialisation of translation parameters is time consuming.
169 // Therefore, default values will only be initialised if they are really needed.
170 // Otherwise, it is left to the user to set the parameter properly.
171 fConvolutedGaussTransitionPars[0] = -999;
172 fConvolutedGaussTransitionPars[1] = -999;
173 fConvolutedGaussTransitionPars[2] = -999;
176 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
177 fFractionHists[i] = 0x0;
178 fFractionSysErrorHists[i] = 0x0;
180 fPtResolution[i] = 0x0;
184 //________________________________________________________________________
185 AliAnalysisTaskPID::AliAnalysisTaskPID(const char *name)
186 : AliAnalysisTaskPIDV0base(name)
188 , fPIDcombined(new AliPIDCombined())
189 , fInputFromOtherTask(kFALSE)
191 , fDoEfficiency(kTRUE)
192 , fDoPtResolution(kTRUE)
193 , fDoDeDxCheck(kTRUE)
194 , fStoreCentralityPercentile(kFALSE)
195 , fStoreAdditionalJetInformation(kFALSE)
196 , fTakeIntoAccountMuons(kFALSE)
200 , fTPCDefaultPriors(kFALSE)
201 , fUseMCidForGeneration(kTRUE)
202 , fUseConvolutedGaus(kFALSE)
203 , fkConvolutedGausNPar(3)
204 , fAccuracyNonGaussianTail(1e-8)
205 , fkDeltaPrimeLowLimit(0.02)
206 , fkDeltaPrimeUpLimit(40.0)
207 , fConvolutedGausDeltaPrime(0x0)
211 , fPileUpRejectionType(AliAnalysisTaskPIDV0base::kPileUpRejectionOff)
212 , fDoAnySystematicStudiesOnTheExpectedSignal(kFALSE)
213 , fSystematicScalingSplinesThreshold(50.)
214 , fSystematicScalingSplinesBelowThreshold(1.0)
215 , fSystematicScalingSplinesAboveThreshold(1.0)
216 , fSystematicScalingEtaCorrectionMomentumThr(0.35)
217 , fSystematicScalingEtaCorrectionLowMomenta(1.0)
218 , fSystematicScalingEtaCorrectionHighMomenta(1.0)
219 , fSystematicScalingEtaSigmaParaThreshold(250.)
220 , fSystematicScalingEtaSigmaParaBelowThreshold(1.0)
221 , fSystematicScalingEtaSigmaParaAboveThreshold(1.0)
222 , fSystematicScalingMultCorrection(1.0)
223 , fCentralityEstimator("V0M")
230 , fGenRespElDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
231 , fGenRespElDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
232 , fGenRespElDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
233 , fGenRespElDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
234 , fGenRespKaDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
235 , fGenRespKaDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
236 , fGenRespKaDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
237 , fGenRespKaDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
238 , fGenRespPiDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
239 , fGenRespPiDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
240 , fGenRespPiDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
241 , fGenRespPiDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
242 , fGenRespMuDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
243 , fGenRespMuDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
244 , fGenRespMuDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
245 , fGenRespMuDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
246 , fGenRespPrDeltaPrimeEl(new Double_t[fgkMaxNumGenEntries])
247 , fGenRespPrDeltaPrimeKa(new Double_t[fgkMaxNumGenEntries])
248 , fGenRespPrDeltaPrimePi(new Double_t[fgkMaxNumGenEntries])
249 , fGenRespPrDeltaPrimePr(new Double_t[fgkMaxNumGenEntries])
251 , fGenRespElDeltaEl(new Double_t[fgkMaxNumGenEntries])
252 , fGenRespElDeltaKa(new Double_t[fgkMaxNumGenEntries])
253 , fGenRespElDeltaPi(new Double_t[fgkMaxNumGenEntries])
254 , fGenRespElDeltaPr(new Double_t[fgkMaxNumGenEntries])
255 , fGenRespKaDeltaEl(new Double_t[fgkMaxNumGenEntries])
256 , fGenRespKaDeltaKa(new Double_t[fgkMaxNumGenEntries])
257 , fGenRespKaDeltaPi(new Double_t[fgkMaxNumGenEntries])
258 , fGenRespKaDeltaPr(new Double_t[fgkMaxNumGenEntries])
259 , fGenRespPiDeltaEl(new Double_t[fgkMaxNumGenEntries])
260 , fGenRespPiDeltaKa(new Double_t[fgkMaxNumGenEntries])
261 , fGenRespPiDeltaPi(new Double_t[fgkMaxNumGenEntries])
262 , fGenRespPiDeltaPr(new Double_t[fgkMaxNumGenEntries])
263 , fGenRespMuDeltaEl(new Double_t[fgkMaxNumGenEntries])
264 , fGenRespMuDeltaKa(new Double_t[fgkMaxNumGenEntries])
265 , fGenRespMuDeltaPi(new Double_t[fgkMaxNumGenEntries])
266 , fGenRespMuDeltaPr(new Double_t[fgkMaxNumGenEntries])
267 , fGenRespPrDeltaEl(new Double_t[fgkMaxNumGenEntries])
268 , fGenRespPrDeltaKa(new Double_t[fgkMaxNumGenEntries])
269 , fGenRespPrDeltaPi(new Double_t[fgkMaxNumGenEntries])
270 , fGenRespPrDeltaPr(new Double_t[fgkMaxNumGenEntries])
272 , fDeltaPrimeAxis(0x0)
273 , fhMaxEtaVariation(0x0)
274 , fhEventsProcessed(0x0)
275 , fhEventsTriggerSel(0x0)
276 , fhEventsTriggerSelVtxCut(0x0)
277 , fhEventsProcessedNoPileUpRejection(0x0)
278 , fhMCgeneratedYieldsPrimaries(0x0)
286 , fOutputContainer(0x0)
291 AliLog::SetClassDebugLevel("AliAnalysisTaskPID", AliLog::kInfo);
293 fConvolutedGausDeltaPrime = new TF1("convolutedGausDeltaPrime", this, &AliAnalysisTaskPID::ConvolutedGaus,
294 fkDeltaPrimeLowLimit, fkDeltaPrimeUpLimit,
295 fkConvolutedGausNPar, "AliAnalysisTaskPID", "ConvolutedGaus");
297 // Set some arbitrary parameteres, such that the function call will not crash
298 // (although it should not be called with these parameters...)
299 fConvolutedGausDeltaPrime->SetParameter(0, 0);
300 fConvolutedGausDeltaPrime->SetParameter(1, 1);
301 fConvolutedGausDeltaPrime->SetParameter(2, 2);
304 // Initialisation of translation parameters is time consuming.
305 // Therefore, default values will only be initialised if they are really needed.
306 // Otherwise, it is left to the user to set the parameter properly.
307 fConvolutedGaussTransitionPars[0] = -999;
308 fConvolutedGaussTransitionPars[1] = -999;
309 fConvolutedGaussTransitionPars[2] = -999;
312 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
313 fFractionHists[i] = 0x0;
314 fFractionSysErrorHists[i] = 0x0;
316 fPtResolution[i] = 0x0;
319 // Define input and output slots here
320 // Input slot #0 works with a TChain
321 DefineInput(0, TChain::Class());
323 DefineOutput(1, TObjArray::Class());
325 DefineOutput(2, AliCFContainer::Class());
327 DefineOutput(3, TObjArray::Class());
331 //________________________________________________________________________
332 AliAnalysisTaskPID::~AliAnalysisTaskPID()
336 CleanupParticleFractionHistos();
338 delete fOutputContainer;
339 fOutputContainer = 0x0;
344 delete fConvolutedGausDeltaPrime;
345 fConvolutedGausDeltaPrime = 0x0;
347 delete fDeltaPrimeAxis;
348 fDeltaPrimeAxis = 0x0;
350 delete [] fGenRespElDeltaPrimeEl;
351 delete [] fGenRespElDeltaPrimeKa;
352 delete [] fGenRespElDeltaPrimePi;
353 delete [] fGenRespElDeltaPrimePr;
355 fGenRespElDeltaPrimeEl = 0x0;
356 fGenRespElDeltaPrimeKa = 0x0;
357 fGenRespElDeltaPrimePi = 0x0;
358 fGenRespElDeltaPrimePr = 0x0;
360 delete [] fGenRespKaDeltaPrimeEl;
361 delete [] fGenRespKaDeltaPrimeKa;
362 delete [] fGenRespKaDeltaPrimePi;
363 delete [] fGenRespKaDeltaPrimePr;
365 fGenRespKaDeltaPrimeEl = 0x0;
366 fGenRespKaDeltaPrimeKa = 0x0;
367 fGenRespKaDeltaPrimePi = 0x0;
368 fGenRespKaDeltaPrimePr = 0x0;
370 delete [] fGenRespPiDeltaPrimeEl;
371 delete [] fGenRespPiDeltaPrimeKa;
372 delete [] fGenRespPiDeltaPrimePi;
373 delete [] fGenRespPiDeltaPrimePr;
375 fGenRespPiDeltaPrimeEl = 0x0;
376 fGenRespPiDeltaPrimeKa = 0x0;
377 fGenRespPiDeltaPrimePi = 0x0;
378 fGenRespPiDeltaPrimePr = 0x0;
380 delete [] fGenRespMuDeltaPrimeEl;
381 delete [] fGenRespMuDeltaPrimeKa;
382 delete [] fGenRespMuDeltaPrimePi;
383 delete [] fGenRespMuDeltaPrimePr;
385 fGenRespMuDeltaPrimeEl = 0x0;
386 fGenRespMuDeltaPrimeKa = 0x0;
387 fGenRespMuDeltaPrimePi = 0x0;
388 fGenRespMuDeltaPrimePr = 0x0;
390 delete [] fGenRespPrDeltaPrimeEl;
391 delete [] fGenRespPrDeltaPrimeKa;
392 delete [] fGenRespPrDeltaPrimePi;
393 delete [] fGenRespPrDeltaPrimePr;
395 fGenRespPrDeltaPrimeEl = 0x0;
396 fGenRespPrDeltaPrimeKa = 0x0;
397 fGenRespPrDeltaPrimePi = 0x0;
398 fGenRespPrDeltaPrimePr = 0x0;
400 delete fhMaxEtaVariation;
401 fhMaxEtaVariation = 0x0;
403 /*OLD with deltaSpecies
404 delete [] fGenRespElDeltaEl;
405 delete [] fGenRespElDeltaKa;
406 delete [] fGenRespElDeltaPi;
407 delete [] fGenRespElDeltaPr;
409 fGenRespElDeltaEl = 0x0;
410 fGenRespElDeltaKa = 0x0;
411 fGenRespElDeltaPi = 0x0;
412 fGenRespElDeltaPr = 0x0;
414 delete [] fGenRespKaDeltaEl;
415 delete [] fGenRespKaDeltaKa;
416 delete [] fGenRespKaDeltaPi;
417 delete [] fGenRespKaDeltaPr;
419 fGenRespKaDeltaEl = 0x0;
420 fGenRespKaDeltaKa = 0x0;
421 fGenRespKaDeltaPi = 0x0;
422 fGenRespKaDeltaPr = 0x0;
424 delete [] fGenRespPiDeltaEl;
425 delete [] fGenRespPiDeltaKa;
426 delete [] fGenRespPiDeltaPi;
427 delete [] fGenRespPiDeltaPr;
429 fGenRespPiDeltaEl = 0x0;
430 fGenRespPiDeltaKa = 0x0;
431 fGenRespPiDeltaPi = 0x0;
432 fGenRespPiDeltaPr = 0x0;
434 delete [] fGenRespMuDeltaEl;
435 delete [] fGenRespMuDeltaKa;
436 delete [] fGenRespMuDeltaPi;
437 delete [] fGenRespMuDeltaPr;
439 fGenRespMuDeltaEl = 0x0;
440 fGenRespMuDeltaKa = 0x0;
441 fGenRespMuDeltaPi = 0x0;
442 fGenRespMuDeltaPr = 0x0;
444 delete [] fGenRespPrDeltaEl;
445 delete [] fGenRespPrDeltaKa;
446 delete [] fGenRespPrDeltaPi;
447 delete [] fGenRespPrDeltaPr;
449 fGenRespPrDeltaEl = 0x0;
450 fGenRespPrDeltaKa = 0x0;
451 fGenRespPrDeltaPi = 0x0;
452 fGenRespPrDeltaPr = 0x0;
457 //________________________________________________________________________
458 void AliAnalysisTaskPID::SetUpPIDcombined()
460 // Initialise the PIDcombined object
462 if (!fDoPID && !fDoDeDxCheck)
466 printf("File: %s, Line: %d: SetUpPIDcombined\n", (char*)__FILE__, __LINE__);
469 AliFatal("No PIDcombined object!\n");
473 fPIDcombined->SetSelectedSpecies(AliPID::kSPECIESC);
474 fPIDcombined->SetEnablePriors(fUsePriors);
476 if (fTPCDefaultPriors)
477 fPIDcombined->SetDefaultTPCPriors();
479 //TODO use individual priors...
481 // Change detector mask (TPC,TOF,ITS)
482 Int_t detectorMask = AliPIDResponse::kDetTPC;
484 // Reject mismatch mask - mismatch only relevant for TOF at the moment - other detectors do not use it
485 Int_t rejectMismatchMask = AliPIDResponse::kDetTPC;
489 detectorMask = detectorMask | AliPIDResponse::kDetITS;
490 rejectMismatchMask = rejectMismatchMask | AliPIDResponse::kDetITS;
493 detectorMask = detectorMask | AliPIDResponse::kDetTOF;
494 rejectMismatchMask = rejectMismatchMask | AliPIDResponse::kDetTOF;
497 fPIDcombined->SetDetectorMask(detectorMask);
498 fPIDcombined->SetRejectMismatchMask(rejectMismatchMask);
501 printf("File: %s, Line: %d: SetUpPIDcombined done\n", (char*)__FILE__, __LINE__);
505 //________________________________________________________________________
506 Bool_t AliAnalysisTaskPID::CalculateMaxEtaVariationMapFromPIDResponse()
508 // Calculate the maximum deviation from unity of the eta correction factors for each row in 1/dEdx(splines)
509 // from the eta correction map of the TPCPIDResponse. The result is stored in fhMaxEtaVariation.
512 AliError("No PID response!");
516 delete fhMaxEtaVariation;
518 const TH2D* hEta = fPIDResponse->GetTPCResponse().GetEtaCorrMap();
520 AliError("No eta correction map!");
524 // Take binning from hEta in Y for fhMaxEtaVariation
525 fhMaxEtaVariation = hEta->ProjectionY("hMaxEtaVariation");
526 fhMaxEtaVariation->SetDirectory(0);
527 fhMaxEtaVariation->Reset();
529 // For each bin in 1/dEdx, loop of all tanTheta bins and find the maximum deviation from unity.
530 // Store the result in fhMaxEtaVariation
532 for (Int_t binY = 1; binY <= fhMaxEtaVariation->GetNbinsX(); binY++) {
533 Double_t maxAbs = -1;
534 for (Int_t binX = 1; binX <= hEta->GetNbinsX(); binX++) {
535 Double_t curr = TMath::Abs(hEta->GetBinContent(binX, binY) - 1.);
540 if (maxAbs < 1e-12) {
541 AliError(Form("Maximum deviation from unity is zero for 1/dEdx = %f (bin %d)", hEta->GetYaxis()->GetBinCenter(binY), binY));
542 delete fhMaxEtaVariation;
546 fhMaxEtaVariation->SetBinContent(binY, maxAbs);
549 printf("AliAnalysisTaskPID: Calculated max eta variation from map \"%s\".\n", hEta->GetTitle());
555 //________________________________________________________________________
556 void AliAnalysisTaskPID::UserCreateOutputObjects()
562 printf("File: %s, Line: %d: UserCreateOutputObjects\n", (char*)__FILE__, __LINE__);
564 // Setup basic things, like PIDResponse
565 AliAnalysisTaskPIDV0base::UserCreateOutputObjects();
568 AliFatal("PIDResponse object was not created");
575 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(1) successful\n", (char*)__FILE__, __LINE__);
577 fOutputContainer = new TObjArray(1);
578 fOutputContainer->SetName(GetName());
579 fOutputContainer->SetOwner(kTRUE);
581 const Int_t nPtBins = 68;
582 Double_t binsPt[nPtBins+1] = {0. , 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45,
583 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95,
584 1.0, 1.1 , 1.2, 1.3 , 1.4, 1.5 , 1.6, 1.7 , 1.8, 1.9 ,
585 2.0, 2.2 , 2.4, 2.6 , 2.8, 3.0 , 3.2, 3.4 , 3.6, 3.8 ,
586 4.0, 4.5 , 5.0, 5.5 , 6.0, 6.5 , 7.0, 8.0 , 9.0, 10.0,
587 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0,
588 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0 };
590 const Int_t nCentBins = 12;
591 //-1 for pp (unless explicitely requested); 90-100 has huge electro-magnetic impurities
592 Double_t binsCent[nCentBins+1] = {-1, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
594 // This centrality estimator deals with integers! This implies that the ranges are always [lowlim, uplim - 1]
595 Double_t binsCentITSTPCTracklets[nCentBins+1] = { 0, 7, 13, 20, 29, 40, 50, 60, 72, 83, 95, 105, 115 };
597 if (fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0 && fStoreCentralityPercentile) {
598 // Special binning for this centrality estimator; but keep number of bins!
599 for (Int_t i = 0; i < nCentBins+1; i++)
600 binsCent[i] = binsCentITSTPCTracklets[i];
603 const Int_t nJetPtBins = 11;
604 Double_t binsJetPt[nJetPtBins+1] = {0, 2, 5, 10, 15, 20, 30, 40, 60, 80, 120, 200};
606 const Int_t nChargeBins = 2;
607 const Double_t binsCharge[nChargeBins+1] = { -1.0 - 1e-4, 0.0, 1.0 + 1e-4 };
609 const Int_t nBinsJets = kDataNumAxes;
610 const Int_t nBinsNoJets = nBinsJets - fgkNumJetAxes;
612 const Int_t nBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
614 // deltaPrimeSpecies binning
615 const Int_t deltaPrimeNBins = 600;
616 Double_t deltaPrimeBins[deltaPrimeNBins + 1];
618 const Double_t fromLow = fkDeltaPrimeLowLimit;
619 const Double_t toHigh = fkDeltaPrimeUpLimit;
620 const Double_t factor = TMath::Power(toHigh/fromLow, 1./deltaPrimeNBins);
622 // Log binning for whole deltaPrime range
623 deltaPrimeBins[0] = fromLow;
624 for (Int_t i = 0 + 1; i <= deltaPrimeNBins; i++) {
625 deltaPrimeBins[i] = factor * deltaPrimeBins[i - 1];
628 fDeltaPrimeAxis = new TAxis(deltaPrimeNBins, deltaPrimeBins);
630 const Int_t nMCPIDbins = 5;
631 const Double_t mcPIDmin = 0.;
632 const Double_t mcPIDmax = 5.;
634 const Int_t nSelSpeciesBins = 4;
635 const Double_t selSpeciesMin = 0.;
636 const Double_t selSpeciesMax = 4.;
638 const Int_t nZBins = 20;
639 const Double_t zMin = 0.;
640 const Double_t zMax = 1.;
642 const Int_t nXiBins = 70;
643 const Double_t xiMin = 0.;
644 const Double_t xiMax = 7.;
646 const Int_t nTOFpidInfoBins = kNumTOFpidInfoBins;
647 const Double_t tofPIDinfoMin = kNoTOFinfo;
648 const Double_t tofPIDinfoMax = kNoTOFinfo + kNumTOFpidInfoBins;
650 // MC PID, SelectSpecies, pT, deltaPrimeSpecies, centrality percentile, jet pT, z = track_pT/jet_pT, xi = log(1/z)
651 Int_t binsNoJets[nBinsNoJets] = { nMCPIDbins,
659 Int_t binsJets[nBinsJets] = { nMCPIDbins,
670 Int_t *bins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
672 Double_t xminNoJets[nBinsNoJets] = { mcPIDmin,
680 Double_t xminJets[nBinsJets] = { mcPIDmin,
691 Double_t *xmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
693 Double_t xmaxNoJets[nBinsNoJets] = { mcPIDmax,
696 deltaPrimeBins[deltaPrimeNBins],
698 binsCharge[nChargeBins],
701 Double_t xmaxJets[nBinsJets] = { mcPIDmax,
704 deltaPrimeBins[deltaPrimeNBins],
706 binsJetPt[nJetPtBins],
709 binsCharge[nChargeBins],
712 Double_t *xmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
714 fConvolutedGausDeltaPrime->SetNpx(deltaPrimeNBins);
717 fhPIDdataAll = new THnSparseD("hPIDdataAll","", nBins, bins, xmin, xmax);
718 SetUpHist(fhPIDdataAll, binsPt, deltaPrimeBins, binsCent, binsJetPt);
719 fOutputContainer->Add(fhPIDdataAll);
722 // Generated histograms (so far, bins are the same as for primary THnSparse)
723 const Int_t nGenBins = fStoreAdditionalJetInformation ? nBinsJets : nBinsNoJets;
724 // MC PID, SelectSpecies, Pt, deltaPrimeSpecies, jet pT, z = track_pT/jet_pT, xi = log(1/z)
726 Int_t *genBins = fStoreAdditionalJetInformation ? &binsJets[0] : &binsNoJets[0];
727 Double_t *genXmin = fStoreAdditionalJetInformation? &xminJets[0] : &xminNoJets[0];
728 Double_t *genXmax = fStoreAdditionalJetInformation? &xmaxJets[0] : &xmaxNoJets[0];
731 fhGenEl = new THnSparseD("hGenEl", "", nGenBins, genBins, genXmin, genXmax);
732 SetUpGenHist(fhGenEl, binsPt, deltaPrimeBins, binsCent, binsJetPt);
733 fOutputContainer->Add(fhGenEl);
735 fhGenKa = new THnSparseD("hGenKa", "", nGenBins, genBins, genXmin, genXmax);
736 SetUpGenHist(fhGenKa, binsPt, deltaPrimeBins, binsCent, binsJetPt);
737 fOutputContainer->Add(fhGenKa);
739 fhGenPi = new THnSparseD("hGenPi", "", nGenBins, genBins, genXmin, genXmax);
740 SetUpGenHist(fhGenPi, binsPt, deltaPrimeBins, binsCent, binsJetPt);
741 fOutputContainer->Add(fhGenPi);
743 if (fTakeIntoAccountMuons) {
744 fhGenMu = new THnSparseD("hGenMu", "", nGenBins, genBins, genXmin, genXmax);
745 SetUpGenHist(fhGenMu, binsPt, deltaPrimeBins, binsCent, binsJetPt);
746 fOutputContainer->Add(fhGenMu);
749 fhGenPr = new THnSparseD("hGenPr", "", nGenBins, genBins, genXmin, genXmax);
750 SetUpGenHist(fhGenPr, binsPt, deltaPrimeBins, binsCent, binsJetPt);
751 fOutputContainer->Add(fhGenPr);
755 fhEventsProcessed = new TH1D("fhEventsProcessed",
756 "Number of events passing trigger selection, vtx and zvtx cuts and pile-up rejection;Centrality percentile",
757 nCentBins, binsCent);
758 fhEventsProcessed->Sumw2();
759 fOutputContainer->Add(fhEventsProcessed);
761 fhEventsTriggerSelVtxCut = new TH1D("fhEventsTriggerSelVtxCut",
762 "Number of events passing trigger selection and vtx cut;Centrality percentile",
763 nCentBins, binsCent);
764 fhEventsTriggerSelVtxCut->Sumw2();
765 fOutputContainer->Add(fhEventsTriggerSelVtxCut);
767 fhEventsTriggerSel = new TH1D("fhEventsTriggerSel",
768 "Number of events passing trigger selection;Centrality percentile",
769 nCentBins, binsCent);
770 fOutputContainer->Add(fhEventsTriggerSel);
771 fhEventsTriggerSel->Sumw2();
774 fhEventsProcessedNoPileUpRejection = new TH1D("fhEventsProcessedNoPileUpRejection",
775 "Number of events passing trigger selection, vtx and zvtx cuts;Centrality percentile",
776 nCentBins, binsCent);
777 fOutputContainer->Add(fhEventsProcessedNoPileUpRejection);
778 fhEventsProcessedNoPileUpRejection->Sumw2();
781 // Generated yields within acceptance
782 const Int_t nBinsGenYields = fStoreAdditionalJetInformation ? kGenYieldNumAxes : kGenYieldNumAxes - 3;
783 Int_t genYieldsBins[kGenYieldNumAxes] = { nMCPIDbins, nPtBins, nCentBins, nJetPtBins, nZBins, nXiBins,
785 genYieldsBins[GetIndexOfChargeAxisGenYield()] = nChargeBins;
786 Double_t genYieldsXmin[kGenYieldNumAxes] = { mcPIDmin, binsPt[0], binsCent[0], binsJetPt[0], zMin, xiMin,
788 genYieldsXmin[GetIndexOfChargeAxisGenYield()] = binsCharge[0];
789 Double_t genYieldsXmax[kGenYieldNumAxes] = { mcPIDmax, binsPt[nPtBins], binsCent[nCentBins], binsJetPt[nJetPtBins], zMax, xiMax,
790 binsCharge[nChargeBins] };
791 genYieldsXmax[GetIndexOfChargeAxisGenYield()] = binsCharge[nChargeBins];
794 fhMCgeneratedYieldsPrimaries = new THnSparseD("fhMCgeneratedYieldsPrimaries",
795 "Generated yields w/o reco and cuts inside acceptance (physical primaries)",
796 nBinsGenYields, genYieldsBins, genYieldsXmin, genYieldsXmax);
797 SetUpGenYieldHist(fhMCgeneratedYieldsPrimaries, binsPt, binsCent, binsJetPt);
798 fOutputContainer->Add(fhMCgeneratedYieldsPrimaries);
801 // Container with several process steps (generated and reconstructed level with some variations)
806 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(2) successful\n", (char*)__FILE__, __LINE__);
808 // Array for the number of bins in each dimension
809 // Dimensions: MC-ID, trackPt, trackEta, trackCharge, cenrality percentile, jetPt, z, xi TODO phi???
810 const Int_t nEffDims = fStoreAdditionalJetInformation ? kEffNumAxes : kEffNumAxes - 3; // Number of dimensions for the efficiency
812 const Int_t nMCIDbins = AliPID::kSPECIES;
813 Double_t binsMCID[nMCIDbins + 1];
815 for(Int_t i = 0; i <= nMCIDbins; i++) {
819 const Int_t nEtaBins = 18;
820 const Double_t binsEta[nEtaBins+1] = {-0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
821 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };
823 const Int_t nEffBins[kEffNumAxes] = { nMCIDbins, nPtBins, nEtaBins, nChargeBins, nCentBins, nJetPtBins, nZBins, nXiBins };
825 fContainerEff = new AliCFContainer("containerEff", "Reconstruction Efficiency x Acceptance x Resolution and Secondary Correction",
826 kNumSteps, nEffDims, nEffBins);
828 // Setting the bin limits
829 fContainerEff->SetBinLimits(kEffMCID, binsMCID);
830 fContainerEff->SetBinLimits(kEffTrackPt, binsPt);
831 fContainerEff->SetBinLimits(kEffTrackEta, binsEta);
832 fContainerEff->SetBinLimits(kEffTrackCharge, binsCharge);
833 fContainerEff->SetBinLimits(kEffCentrality, binsCent);
834 if (fStoreAdditionalJetInformation) {
835 fContainerEff->SetBinLimits(kEffJetPt, binsJetPt);
836 fContainerEff->SetBinLimits(kEffZ, zMin, zMax);
837 fContainerEff->SetBinLimits(kEffXi, xiMin, xiMax);
840 fContainerEff->SetVarTitle(kEffMCID,"MC ID");
841 fContainerEff->SetVarTitle(kEffTrackPt,"p_{T} (GeV/c)");
842 fContainerEff->SetVarTitle(kEffTrackEta,"#eta");
843 fContainerEff->SetVarTitle(kEffTrackCharge,"Charge (e_{0})");
844 fContainerEff->SetVarTitle(kEffCentrality, "Centrality Percentile");
845 if (fStoreAdditionalJetInformation) {
846 fContainerEff->SetVarTitle(kEffJetPt, "p_{T}^{jet} (GeV/c)");
847 fContainerEff->SetVarTitle(kEffZ, "z = p_{T}^{track} / p_{T}^{jet}");
848 fContainerEff->SetVarTitle(kEffXi, "#xi = ln(p_{T}^{jet} / p_{T}^{track})");
851 // Define clean MC sample
852 fContainerEff->SetStepTitle(kStepGenWithGenCuts, "Particle level, cuts on particle level");
853 // For Acceptance x Efficiency correction of primaries
854 fContainerEff->SetStepTitle(kStepRecWithGenCuts, "Detector level (rec) with cuts on particle level");
855 // For (pT) resolution correction
856 fContainerEff->SetStepTitle(kStepRecWithGenCutsMeasuredObs,
857 "Detector level (rec) with cuts on particle level with measured observables");
858 // For secondary correction
859 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObs,
860 "Detector level, all cuts on detector level with measured observables");
861 fContainerEff->SetStepTitle(kStepRecWithRecCutsPrimaries,
862 "Detector level, all cuts on detector level, only MC primaries");
863 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsPrimaries,
864 "Detector level, all cuts on detector level with measured observables, only MC primaries");
865 fContainerEff->SetStepTitle(kStepRecWithRecCutsMeasuredObsStrangenessScaled,
866 "Detector level (strangeness scaled), all cuts on detector level with measured observables");
869 if (fDoPID || fDoEfficiency) {
871 fh2FFJetPtRec = new TH2D("fh2FFJetPtRec", "Number of reconstructed jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
872 nCentBins, binsCent, nJetPtBins, binsJetPt);
873 fh2FFJetPtRec->Sumw2();
874 fOutputContainer->Add(fh2FFJetPtRec);
875 fh2FFJetPtGen = new TH2D("fh2FFJetPtGen", "Number of generated jets;Centrality Percentile;p_{T}^{jet} (GeV/c)",
876 nCentBins, binsCent, nJetPtBins, binsJetPt);
877 fh2FFJetPtGen->Sumw2();
878 fOutputContainer->Add(fh2FFJetPtGen);
881 // Pythia information
882 fh1Xsec = new TProfile("fh1Xsec", "xsec from pyxsec.root", 1, 0, 1);
884 fh1Xsec->GetXaxis()->SetBinLabel(1, "<#sigma>");
885 fh1Trials = new TH1D("fh1Trials", "trials from pyxsec.root", 1, 0, 1);
887 fh1Trials->GetXaxis()->SetBinLabel(1, "#sum{ntrials}");
889 fOutputContainer->Add(fh1Xsec);
890 fOutputContainer->Add(fh1Trials);
892 if (fDoDeDxCheck || fDoPtResolution) {
894 fQAContainer = new TObjArray(1);
895 fQAContainer->SetName(Form("%s_QA", GetName()));
896 fQAContainer->SetOwner(kTRUE);
899 printf("File: %s, Line: %d: UserCreateOutputObjects -> OpenFile(3) successful\n", (char*)__FILE__, __LINE__);
902 if (fDoPtResolution) {
903 const Int_t nPtBinsRes = 100;
904 Double_t pTbinsRes[nPtBinsRes + 1];
906 const Double_t fromLowPtRes = 0.15;
907 const Double_t toHighPtRes = 50.;
908 const Double_t factorPtRes = TMath::Power(toHighPtRes/fromLowPtRes, 1./nPtBinsRes);
909 // Log binning for whole pT range
910 pTbinsRes[0] = fromLowPtRes;
911 for (Int_t i = 0 + 1; i <= nPtBinsRes; i++) {
912 pTbinsRes[i] = factorPtRes * pTbinsRes[i - 1];
915 const Int_t nBinsPtResolution = kPtResNumAxes;
916 Int_t ptResolutionBins[kPtResNumAxes] = { nJetPtBins, nPtBinsRes, nPtBinsRes,
917 nChargeBins, nCentBins };
918 Double_t ptResolutionXmin[kPtResNumAxes] = { binsJetPt[0], pTbinsRes[0], pTbinsRes[0],
919 binsCharge[0], binsCent[0] };
920 Double_t ptResolutionXmax[kPtResNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], pTbinsRes[nPtBinsRes],
921 binsCharge[nChargeBins], binsCent[nCentBins] };
923 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
924 fPtResolution[i] = new THnSparseD(Form("fPtResolution_%s", AliPID::ParticleShortName(i)),
925 Form("Pt resolution for primaries, %s", AliPID::ParticleLatexName(i)),
926 nBinsPtResolution, ptResolutionBins, ptResolutionXmin, ptResolutionXmax);
927 SetUpPtResHist(fPtResolution[i], pTbinsRes, binsJetPt, binsCent);
928 fQAContainer->Add(fPtResolution[i]);
932 // Besides the pT resolution, also perform check on shared clusters
933 const Int_t nBinsQASharedCls = kQASharedClsNumAxes;
934 Int_t qaSharedClsBins[kQASharedClsNumAxes] = { nJetPtBins, nPtBinsRes, 160, 160 };
935 Double_t qaSharedClsXmin[kQASharedClsNumAxes] = { binsJetPt[0], pTbinsRes[0], 0, -1 };
936 Double_t qaSharedClsXmax[kQASharedClsNumAxes] = { binsJetPt[nJetPtBins], pTbinsRes[nPtBinsRes], 160, 159 };
938 fQASharedCls = new THnSparseD("fQASharedCls", "QA shared clusters", nBinsQASharedCls, qaSharedClsBins, qaSharedClsXmin, qaSharedClsXmax);
940 SetUpSharedClsHist(fQASharedCls, pTbinsRes, binsJetPt);
941 fQAContainer->Add(fQASharedCls);
947 const Int_t nEtaAbsBins = 9;
948 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 };
950 const Double_t dEdxMin = 20;
951 const Double_t dEdxMax = 110;
952 const Int_t nDeDxBins = (Int_t) ((dEdxMax - dEdxMin) / 0.02);
953 const Int_t nBinsDeDxCheck= kDeDxCheckNumAxes;
954 Int_t dEdxCheckBins[kDeDxCheckNumAxes] = { nSelSpeciesBins, nPtBins, nJetPtBins, nEtaAbsBins, nDeDxBins };
955 Double_t dEdxCheckXmin[kDeDxCheckNumAxes] = { selSpeciesMin, binsPt[0], binsJetPt[0], binsEtaAbs[0], dEdxMin };
956 Double_t dEdxCheckXmax[kDeDxCheckNumAxes] = { selSpeciesMax, binsPt[nPtBins], binsJetPt[nJetPtBins], binsEtaAbs[nEtaAbsBins], dEdxMax };
958 fDeDxCheck = new THnSparseD("fDeDxCheck", "dEdx check", nBinsDeDxCheck, dEdxCheckBins, dEdxCheckXmin, dEdxCheckXmax);
959 SetUpDeDxCheckHist(fDeDxCheck, binsPt, binsJetPt, binsEtaAbs);
960 fQAContainer->Add(fDeDxCheck);
964 printf("File: %s, Line: %d: UserCreateOutputObjects -> Posting output data\n", (char*)__FILE__, __LINE__);
966 PostData(1, fOutputContainer);
968 PostData(2, fContainerEff);
969 if (fDoDeDxCheck || fDoPtResolution)
970 PostData(3, fQAContainer);
973 printf("File: %s, Line: %d: UserCreateOutputObjects -> Done\n", (char*)__FILE__, __LINE__);
977 //________________________________________________________________________
978 void AliAnalysisTaskPID::UserExec(Option_t *)
981 // Called for each event
984 printf("File: %s, Line: %d: UserExec\n", (char*)__FILE__, __LINE__);
986 // No processing of event, if input is fed in directly from another task
987 if (fInputFromOtherTask)
991 printf("File: %s, Line: %d: UserExec -> Processing started\n", (char*)__FILE__, __LINE__);
993 fEvent = dynamic_cast<AliVEvent*>(InputEvent());
995 Printf("ERROR: fEvent not available");
999 ConfigureTaskForCurrentEvent(fEvent);
1001 fMC = dynamic_cast<AliMCEvent*>(MCEvent());
1003 if (!fPIDResponse || !fPIDcombined)
1006 Double_t centralityPercentile = -1;
1007 if (fStoreCentralityPercentile) {
1008 if (fCentralityEstimator.CompareTo("ITSTPCtracklets", TString::kIgnoreCase) == 0) {
1009 // Special pp centrality estimator
1010 AliESDEvent* esdEvent = dynamic_cast<AliESDEvent*>(fEvent);
1012 AliError("Not esd event -> Cannot use tracklet multiplicity estimator!");
1013 centralityPercentile = -1;
1016 centralityPercentile = AliESDtrackCuts::GetReferenceMultiplicity(esdEvent, AliESDtrackCuts::kTrackletsITSTPC, fEtaAbsCutUp);
1020 centralityPercentile = fEvent->GetCentrality()->GetCentralityPercentile(fCentralityEstimator.Data());
1023 IncrementEventCounter(centralityPercentile, kTriggerSel);
1025 // Check if vertex is ok, but don't apply cut on z position
1026 if (!GetVertexIsOk(fEvent, kFALSE))
1029 fESD = dynamic_cast<AliESDEvent*>(fEvent);
1030 const AliVVertex* primaryVertex = fESD ? fESD->GetPrimaryVertexTracks() : fEvent->GetPrimaryVertex();
1034 if(primaryVertex->GetNContributors() <= 0)
1037 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCut);
1039 // Now check again, but also require z position to be in desired range
1040 if (!GetVertexIsOk(fEvent, kTRUE))
1043 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCutNoPileUpRejection);
1044 //TODO ATTENTION: Is this the right place for the pile-up rejection? Important to have still the proper bin-0 correction,
1045 // which is done solely with sel and selVtx, since the zvtx selection does ~not change the spectra. The question is whether the pile-up
1046 // 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
1047 // of events. But if it does change the spectra, this must somehow be corrected for.
1048 if (GetIsPileUp(fEvent, fPileUpRejectionType))
1051 IncrementEventCounter(centralityPercentile, kTriggerSelAndVtxCutAndZvtxCut);
1053 Double_t magField = fEvent->GetMagneticField();
1056 if (fDoPID || fDoEfficiency) {
1057 for (Int_t iPart = 0; iPart < fMC->GetNumberOfTracks(); iPart++) {
1058 AliMCParticle *mcPart = dynamic_cast<AliMCParticle*>(fMC->GetTrack(iPart));
1063 // Define clean MC sample with corresponding particle level track cuts:
1064 // - MC-track must be in desired eta range
1065 // - MC-track must be physical primary
1066 // - Species must be one of those in question (everything else goes to the overflow bin of mcID)
1068 // Geometrie should be the same as on the reconstructed level -> By definition analysis within this eta interval
1069 if (!IsInAcceptedEtaRange(TMath::Abs(mcPart->Eta()))) continue;
1071 Int_t mcID = PDGtoMCID(mcPart->PdgCode());
1073 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1074 Double_t chargeMC = mcPart->Charge() / 3.;
1076 if (TMath::Abs(chargeMC) < 0.01)
1077 continue; // Reject neutral particles (only relevant, if mcID is not used)
1079 if (!fMC->IsPhysicalPrimary(iPart))
1083 Double_t valuesGenYield[kGenYieldNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), centralityPercentile, -1, -1, -1, -1 };
1084 valuesGenYield[GetIndexOfChargeAxisGenYield()] = chargeMC;
1086 fhMCgeneratedYieldsPrimaries->Fill(valuesGenYield);
1090 if (fDoEfficiency) {
1091 Double_t valueEff[kEffNumAxes] = { static_cast<Double_t>(mcID), mcPart->Pt(), mcPart->Eta(), chargeMC, centralityPercentile,
1094 fContainerEff->Fill(valueEff, kStepGenWithGenCuts);
1100 // Track loop to fill a Train spectrum
1101 for (Int_t iTracks = 0; iTracks < fEvent->GetNumberOfTracks(); iTracks++) {
1102 AliVTrack* track = dynamic_cast<AliVTrack*>(fEvent->GetTrack(iTracks));
1104 Printf("ERROR: Could not retrieve track %d", iTracks);
1109 // Apply detector level track cuts
1110 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
1111 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
1112 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
1116 if(fTrackFilter && !fTrackFilter->IsSelected(track))
1119 if (GetUseTPCCutMIGeo()) {
1120 if (!TPCCutMIGeo(track, fEvent))
1123 else if (GetUseTPCnclCut()) {
1124 if (!TPCnclCut(track))
1129 if (!PhiPrimeCut(track, magField))
1130 continue; // reject track
1133 Int_t pdg = 0; // = 0 indicates data for the moment
1134 AliMCParticle* mcTrack = 0x0;
1135 Int_t mcID = AliPID::kUnknown;
1139 label = track->GetLabel();
1144 mcTrack = dynamic_cast<AliMCParticle*>(fMC->GetTrack(TMath::Abs(label)));
1146 Printf("ERROR: Could not retrieve mcTrack with label %d for track %d", label, iTracks);
1150 pdg = mcTrack->PdgCode();
1151 mcID = PDGtoMCID(mcTrack->PdgCode());
1153 if (fDoEfficiency) {
1154 // For efficiency: Reconstructed track has survived all cuts on the detector level (excluding acceptance)
1155 // and has an associated MC track which is a physical primary and was generated inside the acceptance
1156 if (fMC->IsPhysicalPrimary(TMath::Abs(label)) &&
1157 IsInAcceptedEtaRange(TMath::Abs(mcTrack->Eta()))) {
1159 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1160 Double_t value[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3., centralityPercentile,
1162 fContainerEff->Fill(value, kStepRecWithGenCuts);
1164 Double_t valueMeas[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1166 fContainerEff->Fill(valueMeas, kStepRecWithGenCutsMeasuredObs);
1171 // Only process tracks inside the desired eta window
1172 if (!IsInAcceptedEtaRange(TMath::Abs(track->Eta()))) continue;
1174 if (fDoPID || fDoDeDxCheck || fDoPtResolution)
1175 ProcessTrack(track, pdg, centralityPercentile, -1); // No jet information in this case -> Set jet pT to -1
1177 if (fDoPtResolution) {
1178 if (mcTrack && fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1179 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1180 Double_t valuePtRes[kPtResNumAxes] = { -1, mcTrack->Pt(), track->Pt(), mcTrack->Charge() / 3., centralityPercentile };
1181 FillPtResolution(mcID, valuePtRes);
1185 if (fDoEfficiency) {
1187 Double_t valueRecAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), track->Pt(), track->Eta(), static_cast<Double_t>(track->Charge()), centralityPercentile,
1189 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObs);
1191 Double_t weight = IsSecondaryWithStrangeMotherMC(fMC, TMath::Abs(label)) ?
1192 GetMCStrangenessFactorCMS(fMC, mcTrack) : 1.0;
1193 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsStrangenessScaled, weight);
1195 // AliMCParticle->Charge() calls TParticlePDG->Charge(), which returns the charge in units of e0 / 3
1196 Double_t valueGenAllCuts[kEffNumAxes] = { static_cast<Double_t>(mcID), mcTrack->Pt(), mcTrack->Eta(), mcTrack->Charge() / 3.,
1197 centralityPercentile, -1, -1, -1 };
1198 if (fMC->IsPhysicalPrimary(TMath::Abs(label))) {
1199 fContainerEff->Fill(valueRecAllCuts, kStepRecWithRecCutsMeasuredObsPrimaries);
1200 fContainerEff->Fill(valueGenAllCuts, kStepRecWithRecCutsPrimaries);
1207 printf("File: %s, Line: %d: UserExec -> Processing done\n", (char*)__FILE__, __LINE__);
1212 printf("File: %s, Line: %d: UserExec -> Done\n", (char*)__FILE__, __LINE__);
1215 //________________________________________________________________________
1216 void AliAnalysisTaskPID::Terminate(const Option_t *)
1218 // Draw result to the screen
1219 // Called once at the end of the query
1223 //_____________________________________________________________________________
1224 void AliAnalysisTaskPID::CheckDoAnyStematicStudiesOnTheExpectedSignal()
1226 // Check whether at least one scale factor indicates the ussage of systematic studies
1227 // and set internal flag accordingly.
1229 fDoAnySystematicStudiesOnTheExpectedSignal = kFALSE;
1232 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
1233 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
1234 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1238 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1239 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1240 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1244 if ((TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
1245 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon)) {
1246 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1250 if (TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
1251 fDoAnySystematicStudiesOnTheExpectedSignal = kTRUE;
1257 //_____________________________________________________________________________
1258 void AliAnalysisTaskPID::ConfigureTaskForCurrentEvent(AliVEvent* event)
1260 // Configure the task for the current event. In particular, this is needed if the run number changes
1263 AliError("Could not set up task: no event!");
1267 Int_t run = event->GetRunNumber();
1270 // If systematics on eta is investigated, need to calculate the maxEtaVariationMap
1271 if ((TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon) ||
1272 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon)) {
1273 if (!CalculateMaxEtaVariationMapFromPIDResponse())
1274 AliFatal("Systematics on eta correction requested, but failed to calculate max eta varation map!");
1282 //_____________________________________________________________________________
1283 Int_t AliAnalysisTaskPID::PDGtoMCID(Int_t pdg)
1285 // Returns the corresponding AliPID index to the given pdg code.
1286 // Returns AliPID::kUnkown if pdg belongs to a not considered species.
1288 Int_t absPDGcode = TMath::Abs(pdg);
1289 if (absPDGcode == 211) {//Pion
1290 return AliPID::kPion;
1292 else if (absPDGcode == 321) {//Kaon
1293 return AliPID::kKaon;
1295 else if (absPDGcode == 2212) {//Proton
1296 return AliPID::kProton;
1298 else if (absPDGcode == 11) {//Electron
1299 return AliPID::kElectron;
1301 else if (absPDGcode == 13) {//Muon
1302 return AliPID::kMuon;
1305 return AliPID::kUnknown;
1309 //_____________________________________________________________________________
1310 void AliAnalysisTaskPID::GetJetTrackObservables(Double_t trackPt, Double_t jetPt, Double_t& z, Double_t& xi)
1312 // Uses trackPt and jetPt to obtain z and xi.
1314 z = (jetPt > 0 && trackPt >= 0) ? (trackPt / jetPt) : -1;
1315 xi = (z > 0) ? TMath::Log(1. / z) : -1;
1317 if(trackPt > (1. - 1e-06) * jetPt && trackPt < (1. + 1e-06) * jetPt) { // case z=1 : move entry to last histo bin <1
1324 //_____________________________________________________________________________
1325 void AliAnalysisTaskPID::CleanupParticleFractionHistos()
1327 // Delete histos with particle fractions
1329 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1330 delete fFractionHists[i];
1331 fFractionHists[i] = 0x0;
1333 delete fFractionSysErrorHists[i];
1334 fFractionSysErrorHists[i] = 0x0;
1339 //_____________________________________________________________________________
1340 Double_t AliAnalysisTaskPID::ConvolutedGaus(const Double_t* xx, const Double_t* par) const
1342 // Convolutes gauss with an exponential tail which describes dEdx-response better than pure gaussian
1344 const Double_t mean = par[0];
1345 const Double_t sigma = par[1];
1346 const Double_t lambda = par[2];
1349 printf("File: %s, Line: %d: ConvolutedGaus: mean %e, sigma %e, lambda %e\n", (char*)__FILE__, __LINE__, mean, sigma, lambda);
1351 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);
1355 //_____________________________________________________________________________
1356 inline Double_t AliAnalysisTaskPID::FastGaus(Double_t x, Double_t mean, Double_t sigma) const
1358 // Calculate an unnormalised gaussian function with mean and sigma.
1360 if (sigma < fgkEpsilon)
1363 const Double_t arg = (x - mean) / sigma;
1364 return exp(-0.5 * arg * arg);
1368 //_____________________________________________________________________________
1369 inline Double_t AliAnalysisTaskPID::FastNormalisedGaus(Double_t x, Double_t mean, Double_t sigma) const
1371 // Calculate a normalised (divided by sqrt(2*Pi)*sigma) gaussian function with mean and sigma.
1373 if (sigma < fgkEpsilon)
1376 const Double_t arg = (x - mean) / sigma;
1377 const Double_t res = exp(-0.5 * arg * arg);
1378 return res / (2.50662827463100024 * sigma); //sqrt(2*Pi)=2.50662827463100024
1382 //_____________________________________________________________________________
1383 Int_t AliAnalysisTaskPID::FindBinWithinRange(TAxis* axis, Double_t value) const
1385 // Find the corresponding bin of the axis. Values outside the range (also under and overflow) will be set to the first/last
1388 Int_t bin = axis->FindFixBin(value);
1392 if (bin > axis->GetNbins())
1393 bin = axis->GetNbins();
1399 //_____________________________________________________________________________
1400 Int_t AliAnalysisTaskPID::FindFirstBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1403 // Kind of projects a TH3 to 1 bin combination in y and z
1404 // and looks for the first x bin above a threshold for this projection.
1405 // If no such bin is found, -1 is returned.
1410 Int_t nBinsX = hist->GetNbinsX();
1411 for (Int_t xBin = 1; xBin <= nBinsX; xBin++) {
1412 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1420 //_____________________________________________________________________________
1421 Int_t AliAnalysisTaskPID::FindLastBinAboveIn3dSubset(const TH3* hist, Double_t threshold, Int_t yBin,
1424 // Kind of projects a TH3 to 1 bin combination in y and z
1425 // and looks for the last x bin above a threshold for this projection.
1426 // If no such bin is found, -1 is returned.
1431 Int_t nBinsX = hist->GetNbinsX();
1432 for (Int_t xBin = nBinsX; xBin >= 1; xBin--) {
1433 if (hist->GetBinContent(xBin, yBin, zBin) > threshold)
1441 //_____________________________________________________________________________
1442 Bool_t AliAnalysisTaskPID::GetParticleFraction(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1443 AliPID::EParticleType species,
1444 Double_t& fraction, Double_t& fractionErrorStat, Double_t& fractionErrorSys) const
1446 // Computes the particle fraction for the corresponding species for the given trackPt, jetPt and centrality.
1447 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1448 // On success (return value kTRUE), fraction contains the particle fraction, fractionErrorStat(Sys) the sigma of its
1449 // statistical (systematic) error
1452 fractionErrorStat = 999.;
1453 fractionErrorSys = 999.;
1455 if (species > AliPID::kProton || species < AliPID::kElectron) {
1456 AliError(Form("Only fractions for species index %d to %d availabe, but not for the requested one: %d", 0, AliPID::kProton, species));
1460 if (!fFractionHists[species]) {
1461 AliError(Form("Histo with particle fractions for species %d not loaded!", species));
1466 Int_t jetPtBin = FindBinWithinRange(fFractionHists[species]->GetYaxis(), jetPt);
1467 Int_t centBin = FindBinWithinRange(fFractionHists[species]->GetZaxis(), centralityPercentile);
1469 // The following interpolation takes the bin content of the first/last available bin,
1470 // if requested point lies beyond bin center of first/last bin.
1471 // The interpolation is only done for the x-axis (track pT), i.e. jetPtBin and centBin are fix,
1472 // because the analysis will anyhow be run in bins of jetPt and centrality and
1473 // it is not desired to correlate different jetPt bins via interpolation.
1475 // The same procedure is used for the error of the fraction
1476 TAxis* xAxis = fFractionHists[species]->GetXaxis();
1478 // No interpolation to values beyond the centers of the first/last bins (we don't know exactly where the spectra start or stop,
1479 // thus, search for the first and last bin above 0.0 to constrain the range
1480 Int_t firstBin = TMath::Max(1, FindFirstBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1481 Int_t lastBin = TMath::Min(fFractionHists[species]->GetNbinsX(),
1482 FindLastBinAboveIn3dSubset(fFractionHists[species], 0.0, jetPtBin, centBin));
1484 if (trackPt <= xAxis->GetBinCenter(firstBin)) {
1485 fraction = fFractionHists[species]->GetBinContent(firstBin, jetPtBin, centBin);
1486 fractionErrorStat = fFractionHists[species]->GetBinError(firstBin, jetPtBin, centBin);
1487 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(firstBin, jetPtBin, centBin) : 0.;
1489 else if (trackPt >= xAxis->GetBinCenter(lastBin)) {
1490 fraction = fFractionHists[species]->GetBinContent(lastBin, jetPtBin, centBin);
1491 fractionErrorStat = fFractionHists[species]->GetBinError(lastBin, jetPtBin, centBin);
1492 fractionErrorSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(lastBin, jetPtBin, centBin) : 0.;
1495 Double_t x0 = 0., x1 = 0., y0 = 0., y1 = 0.;
1496 Double_t y0errStat = 0., y1errStat = 0., y0errSys = 0., y1errSys = 0.;
1497 Int_t trackPtBin = xAxis->FindFixBin(trackPt);
1499 // Linear interpolation between nearest neighbours in trackPt
1500 if (trackPt <= xAxis->GetBinCenter(trackPtBin)) {
1501 y0 = fFractionHists[species]->GetBinContent(trackPtBin - 1, jetPtBin, centBin);
1502 y0errStat = fFractionHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin);
1503 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin - 1, jetPtBin, centBin)
1505 x0 = xAxis->GetBinCenter(trackPtBin - 1);
1506 y1 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1507 y1errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1508 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1510 x1 = xAxis->GetBinCenter(trackPtBin);
1513 y0 = fFractionHists[species]->GetBinContent(trackPtBin, jetPtBin, centBin);
1514 y0errStat = fFractionHists[species]->GetBinError(trackPtBin, jetPtBin, centBin);
1515 y0errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin, jetPtBin, centBin)
1517 x0 = xAxis->GetBinCenter(trackPtBin);
1518 y1 = fFractionHists[species]->GetBinContent(trackPtBin + 1, jetPtBin, centBin);
1519 y1errStat = fFractionHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin);
1520 y1errSys = fFractionSysErrorHists[species] ? fFractionSysErrorHists[species]->GetBinError(trackPtBin + 1, jetPtBin, centBin)
1522 x1 = xAxis->GetBinCenter(trackPtBin + 1);
1525 // Per construction: x0 < trackPt < x1
1526 fraction = y0 + (trackPt - x0) * ((y1 - y0) / (x1 - x0));
1527 fractionErrorStat = y0errStat + (trackPt - x0) * ((y1errStat - y0errStat) / (x1 - x0));
1528 fractionErrorSys = fFractionSysErrorHists[species] ? (y0errSys + (trackPt - x0) * ((y1errSys - y0errSys) / (x1 - x0))) : 0.;
1535 //_____________________________________________________________________________
1536 Bool_t AliAnalysisTaskPID::GetParticleFractions(Double_t trackPt, Double_t jetPt, Double_t centralityPercentile,
1537 Double_t* prob, Int_t smearSpeciesByError,
1538 Int_t takeIntoAccountSpeciesSysError, Bool_t uniformSystematicError) const
1540 // Fills the particle fractions for the given trackPt, jetPt and centrality into "prob".
1541 // Use jetPt = -1 for inclusive spectra and centralityPercentile = -1 for pp.
1542 // If smearSpeciesByError is >= 0 && < AliPID::kSPECIES, the returned fractions will be a random number distributed
1543 // with a gauss with mean being the corresponding particle fraction and sigma it's error for the considered species
1544 // "smearSpeciesByError".
1545 // Note that in this case the fractions for all species will NOT sum up to 1!
1546 // Thus, all other species fractions will be re-scaled weighted with their corresponding statistical error.
1547 // A similar procedure is used for "takeIntoAccountSpeciesSysError": The systematic error of the corresponding species
1548 // is used to generate a random number with uniform distribution in [mean - sysError, mean + sysError] for the new mean
1549 // (in cace of uniformSystematicError = kTRUE, otherwise it will be a gaus(mean, sysError)),
1550 // then the other species will be re-scaled according to their systematic errors.
1551 // First, the systematic error uncertainty procedure will be performed (that is including re-scaling), then the statistical
1552 // uncertainty procedure.
1553 // On success, kTRUE is returned.
1555 if (!prob || smearSpeciesByError >= AliPID::kSPECIES || takeIntoAccountSpeciesSysError >= AliPID::kSPECIES)
1558 Double_t probTemp[AliPID::kSPECIES];
1559 Double_t probErrorStat[AliPID::kSPECIES];
1560 Double_t probErrorSys[AliPID::kSPECIES];
1562 Bool_t success = kTRUE;
1563 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kElectron,
1564 probTemp[AliPID::kElectron], probErrorStat[AliPID::kElectron],
1565 probErrorSys[AliPID::kElectron]);
1566 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kMuon,
1567 probTemp[AliPID::kMuon], probErrorStat[AliPID::kMuon], probErrorSys[AliPID::kMuon]);
1568 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kPion,
1569 probTemp[AliPID::kPion], probErrorStat[AliPID::kPion], probErrorSys[AliPID::kPion]);
1570 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kKaon,
1571 probTemp[AliPID::kKaon], probErrorStat[AliPID::kKaon], probErrorSys[AliPID::kKaon]);
1572 success = success && GetParticleFraction(trackPt, jetPt, centralityPercentile, AliPID::kProton,
1573 probTemp[AliPID::kProton], probErrorStat[AliPID::kProton], probErrorSys[AliPID::kProton]);
1578 // If desired, take into account the systematic error of the corresponding species and re-generate probTemp accordingly
1579 if (takeIntoAccountSpeciesSysError >= 0) {
1580 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1581 Double_t generatedFraction = uniformSystematicError
1582 ? fRandom->Rndm() * 2. * probErrorSys[takeIntoAccountSpeciesSysError]
1583 - probErrorSys[takeIntoAccountSpeciesSysError]
1584 + probTemp[takeIntoAccountSpeciesSysError]
1585 : fRandom->Gaus(probTemp[takeIntoAccountSpeciesSysError],
1586 probErrorSys[takeIntoAccountSpeciesSysError]);
1588 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1589 if (generatedFraction < 0.)
1590 generatedFraction = 0.;
1591 else if (generatedFraction > 1.)
1592 generatedFraction = 1.;
1594 // Calculate difference from original fraction (original fractions sum up to 1!)
1595 Double_t deltaFraction = generatedFraction - probTemp[takeIntoAccountSpeciesSysError];
1597 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1598 if (deltaFraction > 0) {
1599 // Some part will be SUBTRACTED from the other fractions
1600 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1601 if (probTemp[i] - probErrorSys[i] < 0)
1602 probErrorSys[i] = probTemp[i];
1606 // Some part will be ADDED to the other fractions
1607 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1608 if (probTemp[i] + probErrorSys[i] > 1)
1609 probErrorSys[i] = 1. - probTemp[i];
1613 // Compute summed weight of all fractions except for the considered one
1614 Double_t summedWeight = 0.;
1615 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1616 if (i != takeIntoAccountSpeciesSysError)
1617 summedWeight += probErrorSys[i];
1620 // Compute the weight for the other species
1622 if (summedWeight <= 1e-13) {
1623 // If this happens for some reason (it should not!), just assume flat weight
1624 printf("Error: summedWeight (sys error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1625 trackPt, jetPt, centralityPercentile);
1628 Double_t weight[AliPID::kSPECIES];
1629 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1630 if (i != takeIntoAccountSpeciesSysError) {
1631 if (summedWeight > 1e-13)
1632 weight[i] = probErrorSys[i] / summedWeight;
1634 weight[i] = probErrorSys[i] / (AliPID::kSPECIES - 1);
1638 // For the final generated fractions, set the generated value for the considered species
1639 // and the generated value minus delta times statistical weight
1640 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1641 if (i != takeIntoAccountSpeciesSysError)
1642 probTemp[i] = probTemp[i] - weight[i] * deltaFraction;
1644 probTemp[i] = generatedFraction;
1648 // Using the values of probTemp (either the original ones or those after taking into account the systematic error),
1649 // calculate the final fractions - if the statistical error is to be taken into account, smear the corresponding
1650 // fraction. If not, just write probTemp to the final result array.
1651 if (smearSpeciesByError >= 0) {
1652 // Generate random fraction of the considered species "smearSpeciesByError" according to mean and sigma
1653 Double_t generatedFraction = fRandom->Gaus(probTemp[smearSpeciesByError], probErrorStat[smearSpeciesByError]);
1655 // Catch cases with invalid fraction (can happen for large errors), i.e. fraction < 0 or > 1
1656 if (generatedFraction < 0.)
1657 generatedFraction = 0.;
1658 else if (generatedFraction > 1.)
1659 generatedFraction = 1.;
1661 // Calculate difference from original fraction (original fractions sum up to 1!)
1662 Double_t deltaFraction = generatedFraction - probTemp[smearSpeciesByError];
1664 // Fractions must (including errors) lie inside [0,1] -> Adapt weights accordingly by setting the errors
1665 if (deltaFraction > 0) {
1666 // Some part will be SUBTRACTED from the other fractions
1667 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1668 if (probTemp[i] - probErrorStat[i] < 0)
1669 probErrorStat[i] = probTemp[i];
1673 // Some part will be ADDED to the other fractions
1674 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1675 if (probTemp[i] + probErrorStat[i] > 1)
1676 probErrorStat[i] = 1. - probTemp[i];
1680 // Compute summed weight of all fractions except for the considered one
1681 Double_t summedWeight = 0.;
1682 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1683 if (i != smearSpeciesByError)
1684 summedWeight += probErrorStat[i];
1687 // Compute the weight for the other species
1689 if (summedWeight <= 1e-13) {
1690 // If this happens for some reason (it should not!), just assume flat weight
1691 printf("Error: summedWeight (stat error) ~ 0 for trackPt %f, jetPt %f, centralityPercentile %f. Setting flat weight!\n",
1692 trackPt, jetPt, centralityPercentile);
1695 Double_t weight[AliPID::kSPECIES];
1696 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1697 if (i != smearSpeciesByError) {
1698 if (summedWeight > 1e-13)
1699 weight[i] = probErrorStat[i] / summedWeight;
1701 weight[i] = probErrorStat[i] / (AliPID::kSPECIES - 1);
1705 // For the final generated fractions, set the generated value for the considered species
1706 // and the generated value minus delta times statistical weight
1707 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1708 if (i != smearSpeciesByError)
1709 prob[i] = probTemp[i] - weight[i] * deltaFraction;
1711 prob[i] = generatedFraction;
1715 // Just take the generated values
1716 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
1717 prob[i] = probTemp[i];
1721 // Should already be normalised, but make sure that it really is:
1722 Double_t probSum = 0.;
1723 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1730 if (TMath::Abs(probSum - 1.0) > 1e-4) {
1731 printf("Warning: Re-normalising sum of fractions: Sum is %e\n", probSum);
1732 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
1741 //_____________________________________________________________________________
1742 const TH3D* AliAnalysisTaskPID::GetParticleFractionHisto(Int_t species, Bool_t sysError) const
1744 if (species < AliPID::kElectron || species > AliPID::kProton)
1747 return sysError ? fFractionSysErrorHists[species] : fFractionHists[species];
1751 //_____________________________________________________________________________
1752 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(Int_t motherPDG, Double_t motherGenPt)
1754 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1755 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction, which uses
1756 // the following data from CMS pp @ 7 TeV inclusive (JHEP 05 (2011) 064)
1760 const Int_t absMotherPDG = TMath::Abs(motherPDG);
1762 if (absMotherPDG == 310 || absMotherPDG == 321) { // K0s / K+ / K-
1763 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.768049;
1764 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.732933;
1765 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.650298;
1766 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.571332;
1767 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.518734;
1768 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.492543;
1769 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.482704;
1770 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.488056;
1771 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.488861;
1772 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.492862;
1773 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.504332;
1774 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.501858;
1775 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.512970;
1776 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.524131;
1777 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.539130;
1778 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.554101;
1779 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.560348;
1780 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.568869;
1781 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.583310;
1782 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.604818;
1783 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.632630;
1784 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.710070;
1785 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.736365;
1786 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 0.835865;
1789 if (absMotherPDG == 3122) { // Lambda
1790 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.645162;
1791 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.627431;
1792 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.457136;
1793 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.384369;
1794 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.330597;
1795 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.309571;
1796 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.293620;
1797 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.283709;
1798 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.282047;
1799 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.277261;
1800 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.275772;
1801 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.280726;
1802 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.288540;
1803 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.288315;
1804 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.296619;
1805 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.302993;
1806 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.338121;
1807 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.349800;
1808 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.356802;
1809 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.391202;
1810 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.422573;
1811 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.573815;
1812 else if(6.00 <= motherGenPt && motherGenPt < 8.00) fac = 0.786984;
1813 else if(8.00 <= motherGenPt && motherGenPt < 10.00) fac = 1.020021;
1816 if (absMotherPDG == 3312 || absMotherPDG == 3322) { // xi
1817 if (0.00 <= motherGenPt && motherGenPt < 0.20) fac = 0.666620;
1818 else if(0.20 <= motherGenPt && motherGenPt < 0.40) fac = 0.575908;
1819 else if(0.40 <= motherGenPt && motherGenPt < 0.60) fac = 0.433198;
1820 else if(0.60 <= motherGenPt && motherGenPt < 0.80) fac = 0.340901;
1821 else if(0.80 <= motherGenPt && motherGenPt < 1.00) fac = 0.290896;
1822 else if(1.00 <= motherGenPt && motherGenPt < 1.20) fac = 0.236074;
1823 else if(1.20 <= motherGenPt && motherGenPt < 1.40) fac = 0.218681;
1824 else if(1.40 <= motherGenPt && motherGenPt < 1.60) fac = 0.207763;
1825 else if(1.60 <= motherGenPt && motherGenPt < 1.80) fac = 0.222848;
1826 else if(1.80 <= motherGenPt && motherGenPt < 2.00) fac = 0.208806;
1827 else if(2.00 <= motherGenPt && motherGenPt < 2.20) fac = 0.197275;
1828 else if(2.20 <= motherGenPt && motherGenPt < 2.40) fac = 0.183645;
1829 else if(2.40 <= motherGenPt && motherGenPt < 2.60) fac = 0.188788;
1830 else if(2.60 <= motherGenPt && motherGenPt < 2.80) fac = 0.188282;
1831 else if(2.80 <= motherGenPt && motherGenPt < 3.00) fac = 0.207442;
1832 else if(3.00 <= motherGenPt && motherGenPt < 3.20) fac = 0.240388;
1833 else if(3.20 <= motherGenPt && motherGenPt < 3.40) fac = 0.241916;
1834 else if(3.40 <= motherGenPt && motherGenPt < 3.60) fac = 0.208276;
1835 else if(3.60 <= motherGenPt && motherGenPt < 3.80) fac = 0.234550;
1836 else if(3.80 <= motherGenPt && motherGenPt < 4.00) fac = 0.251689;
1837 else if(4.00 <= motherGenPt && motherGenPt < 5.00) fac = 0.310204;
1838 else if(5.00 <= motherGenPt && motherGenPt < 6.00) fac = 0.343492;
1841 const Double_t weight = 1. / fac;
1847 //_____________________________________________________________________________
1848 Double_t AliAnalysisTaskPID::GetMCStrangenessFactorCMS(AliMCEvent* mcEvent, AliMCParticle* daughter)
1850 // Strangeness ratio MC/data as function of mother pt from CMS data in |eta|<2.0
1851 // -> Based on function in PWGJE/AliAnalysisTaskFragmentationFunction
1856 AliMCParticle* currentMother = daughter;
1857 AliMCParticle* currentDaughter = daughter;
1860 // find first primary mother K0s, Lambda or Xi
1862 Int_t daughterPDG = currentDaughter->PdgCode();
1864 Int_t motherLabel = currentDaughter->GetMother();
1865 if(motherLabel >= mcEvent->GetNumberOfTracks()){ // protection
1866 currentMother = currentDaughter;
1870 currentMother = (AliMCParticle*)mcEvent->GetTrack(motherLabel);
1872 if (!currentMother) {
1873 currentMother = currentDaughter;
1877 Int_t motherPDG = currentMother->PdgCode();
1879 // phys. primary found ?
1880 if (mcEvent->IsPhysicalPrimary(motherLabel))
1883 if (TMath::Abs(daughterPDG) == 321) {
1884 // K+/K- e.g. from phi (ref data not feeddown corrected)
1885 currentMother = currentDaughter;
1888 if (TMath::Abs(motherPDG) == 310) {
1889 // K0s e.g. from phi (ref data not feeddown corrected)
1892 if (TMath::Abs(motherPDG) == 3212 && TMath::Abs(daughterPDG) == 3122) {
1893 // Mother Sigma0, daughter Lambda (this case not included in feeddown corr.)
1894 currentMother = currentDaughter;
1898 currentDaughter = currentMother;
1902 Int_t motherPDG = currentMother->PdgCode();
1903 Double_t motherGenPt = currentMother->Pt();
1905 return GetMCStrangenessFactorCMS(motherPDG, motherGenPt);
1909 // _________________________________________________________________________________
1910 AliAnalysisTaskPID::TOFpidInfo AliAnalysisTaskPID::GetTOFType(const AliVTrack* track, Int_t tofMode) const
1912 // Get the (locally defined) particle type judged by TOF
1914 if (!fPIDResponse) {
1915 Printf("ERROR: fPIDResponse not available -> Cannot determine TOF type!");
1919 /*TODO still needs some further thinking how to implement it....
1920 // TOF PID status (kTOFout, kTIME) automatically checked by return value of ComputeTPCProbability;
1921 // also, probability array will be set there (no need to initialise here)
1922 Double_t p[AliPID::kSPECIES];
1923 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->ComputeTPCProbability(track, AliPID::kSPECIES, p);
1924 if (tofStatus != AliPIDResponse::kDetPidOk)
1927 // Do not consider muons
1928 p[AliPID::kMuon] = 0.;
1930 // Probabilities are not normalised yet
1932 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
1938 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
1941 Double_t probThreshold = -999.;
1943 // If there is only one distribution, the threshold corresponds to...
1947 else if (tofMode == 1) { // default
1948 probThreshold = 0.9973; // a 3-sigma inclusion cut
1950 else if (tofMode == 2) {
1955 Printf("ERROR: Bad TOF mode: %d!", tofMode);
1961 ///* OLD: cut with n-sigmas (ATTENTION: Does not take into account properly the TOF tail!)
1962 // Check kTOFout, kTIME, mismatch
1963 const AliPIDResponse::EDetPidStatus tofStatus = fPIDResponse->CheckPIDStatus(AliPIDResponse::kTOF, track);
1964 if (tofStatus != AliPIDResponse::kDetPidOk)
1967 Double_t nsigma[kNumTOFspecies + 1] = { -999., -999., -999., -999. };
1968 nsigma[kTOFpion] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kPion);
1969 nsigma[kTOFkaon] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kKaon);
1970 nsigma[kTOFproton] = fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton);
1972 Double_t inclusion = -999;
1973 Double_t exclusion = -999;
1979 else if (tofMode == 1) { // default
1983 else if (tofMode == 2) {
1988 Printf("ERROR: Bad TOF mode: %d!", tofMode);
1992 // Do not cut on nSigma electron because this would also remove pions in a large pT range.
1993 // The electron contamination of the pion sample can be treated by TPC dEdx fits afterwards.
1994 if (TMath::Abs(nsigma[kTOFpion]) < inclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
1996 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) < inclusion && TMath::Abs(nsigma[kTOFproton]) > exclusion)
1998 if (TMath::Abs(nsigma[kTOFpion]) > exclusion && TMath::Abs(nsigma[kTOFkaon]) > exclusion && TMath::Abs(nsigma[kTOFproton]) < inclusion)
2002 // There are no TOF electrons selected because the purity is rather bad, even for small momenta
2003 // (also a small mismatch probability significantly affects electrons because their fraction
2004 // is small). There is no need for TOF electrons anyway, since the dEdx distribution of kaons and
2005 // protons in a given pT bin (also at the dEdx crossings) is very different from that of electrons.
2006 // This is due to the steeply falling dEdx of p and K with momentum, whereas the electron dEdx stays
2008 // As a result, the TPC fit yields a more accurate electron fraction than the TOF selection can do.
2014 // _________________________________________________________________________________
2015 Bool_t AliAnalysisTaskPID::IsSecondaryWithStrangeMotherMC(AliMCEvent* mcEvent, Int_t partLabel)
2017 // Check whether particle is a secondary with strange mother, i.e. returns kTRUE if a strange mother is found
2018 // and the particle is NOT a physical primary. In all other cases kFALSE is returned
2020 if (!mcEvent || partLabel < 0)
2023 AliMCParticle* part = (AliMCParticle*)mcEvent->GetTrack(partLabel);
2028 if (mcEvent->IsPhysicalPrimary(partLabel))
2031 Int_t iMother = part->GetMother();
2036 AliMCParticle* partM = (AliMCParticle*)mcEvent->GetTrack(iMother);
2040 Int_t codeM = TMath::Abs(partM->PdgCode());
2041 Int_t mfl = Int_t(codeM / TMath::Power(10, Int_t(TMath::Log10(codeM))));
2042 if (mfl == 3 && codeM != 3) // codeM = 3 is for s quark
2049 //_____________________________________________________________________________
2050 Bool_t AliAnalysisTaskPID::SetParticleFractionHisto(const TH3D* hist, Int_t species, Bool_t sysError)
2052 // Store a clone of hist (containing the particle fractions of the corresponding species with statistical error (sysError = kFALSE)
2053 // or systematic error (sysError = kTRUE), respectively), internally
2055 if (species < AliPID::kElectron || species > AliPID::kProton) {
2056 AliError(Form("Only fractions for species index %d to %d can be set, but not for the requested one: %d", 0,
2057 AliPID::kProton, species));
2062 delete fFractionSysErrorHists[species];
2064 fFractionSysErrorHists[species] = new TH3D(*hist);
2067 delete fFractionHists[species];
2069 fFractionHists[species] = new TH3D(*hist);
2076 //_____________________________________________________________________________
2077 Bool_t AliAnalysisTaskPID::SetParticleFractionHistosFromFile(const TString filePathName, Bool_t sysError)
2079 // Loads particle fractions for all species from the desired file and returns kTRUE on success.
2080 // The maps are assumed to be of Type TH3D, to sit in the main directory and to have names
2081 // Form("hFraction_%e", AliPID::ParticleName(i)) for sysError = kFALSE and
2082 // Form("hFractionSysError_%e", AliPID::ParticleName(i)) for sysError = kTRUE.
2084 TFile* f = TFile::Open(filePathName.Data());
2086 std::cout << "Failed to open file with particle fractions \"" << filePathName.Data() << "\"!" << std::endl;
2091 for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
2092 TString histName = Form("hFraction%s_%s", sysError ? "SysError" : "", AliPID::ParticleName(i));
2093 hist = dynamic_cast<TH3D*>(f->Get(histName.Data()));
2095 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2096 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2097 CleanupParticleFractionHistos();
2101 if (!SetParticleFractionHisto(hist, i, sysError)) {
2102 std::cout << "Failed to load particle fractions for " << histName.Data() << "!";
2103 std::cout << std::endl << "Cleaning up particle fraction histos!" << std::endl;
2104 CleanupParticleFractionHistos();
2116 //_____________________________________________________________________________
2117 Double_t AliAnalysisTaskPID::GetMaxEtaVariation(Double_t dEdxSplines)
2119 // Returns the maximum eta variation (i.e. deviation of eta correction factor from unity) for the
2120 // given (spline) dEdx
2122 if (dEdxSplines < 1. || !fhMaxEtaVariation) {
2123 Printf("Error GetMaxEtaVariation: No map or invalid dEdxSplines (%f)!", dEdxSplines);
2127 Int_t bin = fhMaxEtaVariation->GetXaxis()->FindFixBin(1. / dEdxSplines);
2131 if (bin > fhMaxEtaVariation->GetXaxis()->GetNbins())
2132 bin = fhMaxEtaVariation->GetXaxis()->GetNbins();
2134 return fhMaxEtaVariation->GetBinContent(bin);
2138 //_____________________________________________________________________________
2139 Int_t AliAnalysisTaskPID::GetRandomParticleTypeAccordingToParticleFractions(Double_t trackPt, Double_t jetPt,
2140 Double_t centralityPercentile,
2141 Bool_t smearByError,
2142 Bool_t takeIntoAccountSysError) const
2144 // Uses the stored histograms with the particle fractions to generate a random particle type according to these fractions.
2145 // In case of problems (e.g. histo missing), AliPID::kUnknown is returned.
2146 // If smearByError is kTRUE, the used fractions will be random numbers distributed with a gauss with mean
2147 // being the corresponding particle fraction and sigma it's error.
2148 // Note that in this case only the fraction of a random species is varied in this way. The other fractions
2149 // will be re-normalised according their statistical errors.
2150 // The same holds for the systematic error of species "takeIntoAccountSpeciesSysError", but the random number will be
2151 // uniformly distributed within [mean - sys, mean + sys] and the re-normalisation will be weighted with the systematic errors.
2152 // Note that the fractions will be calculated first with only the systematic error taken into account (if desired), including
2153 // re-normalisation. Then, the resulting fractions will be used to calculate the final fractions - either with statistical error
2154 // or without. The species, for which the error will be used for smearing, is the same for sys and stat error.
2156 Double_t prob[AliPID::kSPECIES];
2157 Int_t randomSpecies = (smearByError || takeIntoAccountSysError) ? (Int_t)(fRandom->Rndm() * AliPID::kSPECIES) : -1;
2158 Bool_t success = GetParticleFractions(trackPt, jetPt, centralityPercentile, prob, randomSpecies, randomSpecies);
2161 return AliPID::kUnknown;
2163 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2165 if (rnd <= prob[AliPID::kPion])
2166 return AliPID::kPion;
2167 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon])
2168 return AliPID::kKaon;
2169 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton])
2170 return AliPID::kProton;
2171 else if (rnd <= prob[AliPID::kPion] + prob[AliPID::kKaon] + prob[AliPID::kProton] + prob[AliPID::kElectron])
2172 return AliPID::kElectron;
2174 return AliPID::kMuon; //else it must be a muon (only species left)
2178 //_____________________________________________________________________________
2179 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::GenerateDetectorResponse(AliAnalysisTaskPID::ErrorCode errCode,
2180 Double_t mean, Double_t sigma,
2181 Double_t* responses, Int_t nResponses,
2184 // Generate detector response. If a previous generation was not successful or there is something wrong with this signal generation,
2185 // the function will return kFALSE
2189 // Reset response array
2190 for (Int_t i = 0; i < nResponses; i++)
2191 responses[i] = -999;
2193 if (errCode == kError)
2196 ErrorCode ownErrCode = kNoErrors;
2198 if (fUseConvolutedGaus && !usePureGaus) {
2199 // In case of convoluted gauss, calculate the probability density only once to save a lot of time!
2201 TH1* hProbDensity = 0x0;
2202 ownErrCode = SetParamsForConvolutedGaus(mean, sigma);
2203 if (ownErrCode == kError)
2206 hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
2208 for (Int_t i = 0; i < nResponses; i++) {
2209 responses[i] = hProbDensity->GetRandom();
2210 //responses[i] fConvolutedGausDeltaPrime->GetRandom(); // MUCH slower than using the binned version via the histogram
2214 for (Int_t i = 0; i < nResponses; i++) {
2215 responses[i] = fRandom->Gaus(mean, sigma);
2219 // If forwarded error code was a warning (error case has been handled before), return a warning
2220 if (errCode == kWarning)
2223 return ownErrCode; // Forward success/warning
2227 //_____________________________________________________________________________
2228 void AliAnalysisTaskPID::PrintSettings(Bool_t printSystematicsSettings) const
2230 // Print current settings.
2232 printf("\n\nSettings for task %s:\n", GetName());
2233 printf("Is pPb/Pbp: %d -> %s\n", GetIsPbpOrpPb(), GetIsPbpOrpPb() ? "Adapting vertex cuts" : "Using standard vertex cuts");
2234 printf("Track cuts: %s\n", fTrackFilter ? fTrackFilter->GetTitle() : "-");
2235 printf("Eta cut: %.2f <= |eta| <= %.2f\n", GetEtaAbsCutLow(), GetEtaAbsCutUp());
2236 printf("Phi' cut: %d\n", GetUsePhiCut());
2237 printf("TPCCutMIGeo: %d\n", GetUseTPCCutMIGeo());
2238 if (GetUseTPCCutMIGeo()) {
2239 printf("GetCutGeo: %f\n", GetCutGeo());
2240 printf("GetCutNcr: %f\n", GetCutNcr());
2241 printf("GetCutNcl: %f\n", GetCutNcl());
2243 printf("TPCnclCut: %d\n", GetUseTPCnclCut());
2244 if (GetUseTPCnclCut()) {
2245 printf("GetCutPureNcl: %d\n", GetCutPureNcl());
2250 printf("Centrality estimator: %s\n", GetCentralityEstimator().Data());
2254 printf("Pile up rejection type: %d\n", (Int_t)fPileUpRejectionType);
2258 printf("Use MC-ID for signal generation: %d\n", GetUseMCidForGeneration());
2259 printf("Use ITS: %d\n", GetUseITS());
2260 printf("Use TOF: %d\n", GetUseTOF());
2261 printf("Use priors: %d\n", GetUsePriors());
2262 printf("Use TPC default priors: %d\n", GetUseTPCDefaultPriors());
2263 printf("Use convoluted Gauss: %d\n", GetUseConvolutedGaus());
2264 printf("Accuracy of non-Gaussian tail: %e\n", GetAccuracyNonGaussianTail());
2265 printf("Take into account muons: %d\n", GetTakeIntoAccountMuons());
2266 printf("TOF mode: %d\n", GetTOFmode());
2267 printf("\nParams for transition from gauss to asymmetric shape:\n");
2268 printf("[0]: %e\n", GetConvolutedGaussTransitionPar(0));
2269 printf("[1]: %e\n", GetConvolutedGaussTransitionPar(1));
2270 printf("[2]: %e\n", GetConvolutedGaussTransitionPar(2));
2274 printf("Do PID: %d\n", fDoPID);
2275 printf("Do Efficiency: %d\n", fDoEfficiency);
2276 printf("Do PtResolution: %d\n", fDoPtResolution);
2277 printf("Do dEdxCheck: %d\n", fDoDeDxCheck);
2281 printf("Input from other task: %d\n", GetInputFromOtherTask());
2282 printf("Store additional jet information: %d\n", GetStoreAdditionalJetInformation());
2283 printf("Store centrality percentile: %d", GetStoreCentralityPercentile());
2285 if (printSystematicsSettings)
2286 PrintSystematicsSettings();
2292 //_____________________________________________________________________________
2293 void AliAnalysisTaskPID::PrintSystematicsSettings() const
2295 // Print current settings for systematic studies.
2297 printf("\n\nSettings for systematics for task %s:\n", GetName());
2298 printf("SplinesThr:\t%f\n", GetSystematicScalingSplinesThreshold());
2299 printf("SplinesBelowThr:\t%f\n", GetSystematicScalingSplinesBelowThreshold());
2300 printf("SplinesAboveThr:\t%f\n", GetSystematicScalingSplinesAboveThreshold());
2301 printf("EtaCorrMomThr:\t%f\n", GetSystematicScalingEtaCorrectionMomentumThr());
2302 printf("EtaCorrLowP:\t%f\n", GetSystematicScalingEtaCorrectionLowMomenta());
2303 printf("EtaCorrHighP:\t%f\n", GetSystematicScalingEtaCorrectionHighMomenta());
2304 printf("SigmaParaThr:\t%f\n", GetSystematicScalingEtaSigmaParaThreshold());
2305 printf("SigmaParaBelowThr:\t%f\n", GetSystematicScalingEtaSigmaParaBelowThreshold());
2306 printf("SigmaParaAboveThr:\t%f\n", GetSystematicScalingEtaSigmaParaAboveThreshold());
2307 printf("MultCorr:\t%f\n", GetSystematicScalingMultCorrection());
2308 printf("TOF mode: %d\n", GetTOFmode());
2314 //_____________________________________________________________________________
2315 Bool_t AliAnalysisTaskPID::ProcessTrack(const AliVTrack* track, Int_t particlePDGcode, Double_t centralityPercentile,
2318 // Process the track (generate expected response, fill histos, etc.).
2319 // particlePDGcode == 0 means data. Otherwise, the corresponding MC ID will be assumed.
2321 //Printf("Debug: Task %s is starting to process track: dEdx %f, pTPC %f, eta %f, ncl %d\n", GetName(), track->GetTPCsignal(), track->GetTPCmomentum(),
2322 // track->Eta(), track->GetTPCsignalN());
2325 printf("File: %s, Line: %d: ProcessTrack\n", (char*)__FILE__, __LINE__);
2327 if (!fDoPID && !fDoDeDxCheck && !fDoPtResolution)
2331 printf("File: %s, Line: %d: ProcessTrack -> Processing started\n", (char*)__FILE__, __LINE__);
2333 const Bool_t isMC = (particlePDGcode == 0) ? kFALSE : kTRUE;
2338 if (TMath::Abs(particlePDGcode) == 211) {//Pion
2341 else if (TMath::Abs(particlePDGcode) == 321) {//Kaon
2344 else if (TMath::Abs(particlePDGcode) == 2212) {//Proton
2347 else if (TMath::Abs(particlePDGcode) == 11) {//Electron
2350 else if (TMath::Abs(particlePDGcode) == 13) {//Muon
2353 else // In MC-ID case, set to underflow bin such that the response from this track is only used for unidentified signal generation
2354 // or signal generation with PID response and the track is still there (as in data) - e.g. relevant w.r.t. deuterons.
2355 // This is important to be as much as possible consistent with data. And the tracks can still be removed by disabling the
2356 // underflow bin for the projections
2361 //Double_t p = track->GetP();
2362 const Double_t pTPC = track->GetTPCmomentum();
2363 Double_t pT = track->Pt();
2365 Double_t z = -1, xi = -1;
2366 GetJetTrackObservables(pT, jetPt, z, xi);
2369 Double_t trackCharge = track->Charge();
2372 const Bool_t tuneOnDataTPC = fPIDResponse->IsTunedOnData() &&
2373 ((fPIDResponse->GetTunedOnDataMask() & AliPIDResponse::kDetTPC) == AliPIDResponse::kDetTPC);
2374 Double_t dEdxTPC = tuneOnDataTPC ? fPIDResponse->GetTPCsignalTunedOnData(track) : track->GetTPCsignal();
2378 Printf("Skipping track with strange dEdx value: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), pTPC,
2379 track->Eta(), track->GetTPCsignalN());
2383 // Completely remove tracks from light nuclei defined by el and pr <dEdx> as function of pT.
2384 // A very loose cut to be sure not to throw away electrons and/or protons
2385 Double_t nSigmaPr = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kProton);
2386 Double_t nSigmaEl = fPIDResponse->NumberOfSigmasTPC(track, AliPID::kElectron);
2388 if ((pTPC >= 0.3 && (nSigmaPr > 10 && nSigmaEl > 10)) ||
2389 (pTPC < 0.3 && (nSigmaPr > 15 && nSigmaEl > 15))) {
2391 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",
2392 track->GetTPCsignal(), pTPC, pT, track->Eta(), track->GetTPCsignalN(), nSigmaPr, nSigmaEl);
2397 Double_t dEdxEl, dEdxKa, dEdxPi, dEdxMu, dEdxPr;
2398 Double_t sigmaEl, sigmaKa, sigmaPi, sigmaMu, sigmaPr;
2400 if (fDoAnySystematicStudiesOnTheExpectedSignal) {
2401 // Get the uncorrected signal first and the corresponding correction factors.
2402 // Then modify the correction factors and properly recalculate the corrected dEdx
2404 // Get pure spline values for dEdx_expected, without any correction
2405 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2406 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2407 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2408 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2409 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2410 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault, kFALSE, kFALSE);
2412 // Scale splines, if desired
2413 if ((TMath::Abs(fSystematicScalingSplinesBelowThreshold - 1.0) > fgkEpsilon) ||
2414 (TMath::Abs(fSystematicScalingSplinesAboveThreshold - 1.0) > fgkEpsilon)) {
2416 // Tune turn-on of correction for pions (not so relevant for the other species, since at very large momenta)
2418 Double_t scaleFactor = 1.;
2419 Double_t usedSystematicScalingSplines = 1.;
2421 bg = pTPC / AliPID::ParticleMass(AliPID::kElectron);
2422 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2423 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2424 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2425 dEdxEl *= usedSystematicScalingSplines;
2427 bg = pTPC / AliPID::ParticleMass(AliPID::kKaon);
2428 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2429 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2430 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2431 dEdxKa *= usedSystematicScalingSplines;
2433 bg = pTPC / AliPID::ParticleMass(AliPID::kPion);
2434 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2435 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2436 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2437 dEdxPi *= usedSystematicScalingSplines;
2439 if (fTakeIntoAccountMuons) {
2440 bg = pTPC / AliPID::ParticleMass(AliPID::kMuon);
2441 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2442 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2443 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2444 dEdxMu *= usedSystematicScalingSplines;
2448 bg = pTPC / AliPID::ParticleMass(AliPID::kProton);
2449 scaleFactor = 0.5 * (1. + TMath::Erf((bg - fSystematicScalingSplinesThreshold) / 4.));
2450 usedSystematicScalingSplines = fSystematicScalingSplinesBelowThreshold * (1 - scaleFactor)
2451 + fSystematicScalingSplinesAboveThreshold * scaleFactor;
2452 dEdxPr *= usedSystematicScalingSplines;
2455 // Get the eta correction factors for the (modified) expected dEdx
2456 Double_t etaCorrEl = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxEl) : 1.;
2457 Double_t etaCorrKa = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxKa) : 1.;
2458 Double_t etaCorrPi = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPi) : 1.;
2459 Double_t etaCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCEtaCorrection() ?
2460 fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxMu) : 1.;
2461 Double_t etaCorrPr = fPIDResponse->UseTPCEtaCorrection() ? fPIDResponse->GetTPCResponse().GetEtaCorrectionFast(track, dEdxPr) : 1.;
2463 // Scale eta correction factors, if desired (and eta correction maps are to be used, otherwise it is not possible!)
2464 if (fPIDResponse->UseTPCEtaCorrection() &&
2465 (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - 1.0) > fgkEpsilon ||
2466 TMath::Abs(fSystematicScalingEtaCorrectionLowMomenta - 1.0) > fgkEpsilon)) {
2467 // Since we do not want to scale the splines with this, but only the eta variation, only scale the deviation of the correction factor!
2468 // 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!
2471 // Due to additional azimuthal effects, there is an additional eta dependence for low momenta which is not corrected successfully so far.
2472 // One can assign a different (higher) systematic scale factor for this low-p region and a threshold which separates low- and high-p.
2473 // 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
2474 Double_t usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionHighMomenta;
2476 if (TMath::Abs(fSystematicScalingEtaCorrectionHighMomenta - fSystematicScalingEtaCorrectionLowMomenta) > fgkEpsilon) {
2477 const Double_t fractionHighMomentumScaleFactor = 0.5 * (1. + TMath::Erf((pTPC - fSystematicScalingEtaCorrectionMomentumThr) / 0.1));
2478 usedSystematicScalingEtaCorrection = fSystematicScalingEtaCorrectionLowMomenta * (1 - fractionHighMomentumScaleFactor)
2479 + fSystematicScalingEtaCorrectionHighMomenta * fractionHighMomentumScaleFactor;
2482 Double_t maxEtaVariationEl = GetMaxEtaVariation(dEdxEl);
2483 etaCorrEl = etaCorrEl * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrEl - 1.0) / maxEtaVariationEl);
2485 Double_t maxEtaVariationKa = GetMaxEtaVariation(dEdxKa);
2486 etaCorrKa = etaCorrKa * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrKa - 1.0) / maxEtaVariationKa);
2488 Double_t maxEtaVariationPi = GetMaxEtaVariation(dEdxPi);
2489 etaCorrPi = etaCorrPi * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPi - 1.0) / maxEtaVariationPi);
2491 if (fTakeIntoAccountMuons) {
2492 Double_t maxEtaVariationMu = GetMaxEtaVariation(dEdxMu);
2493 etaCorrMu = etaCorrMu * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrMu - 1.0) / maxEtaVariationMu);
2498 Double_t maxEtaVariationPr = GetMaxEtaVariation(dEdxPr);
2499 etaCorrPr = etaCorrPr * (1.0 + (usedSystematicScalingEtaCorrection - 1.) * (etaCorrPr - 1.0) / maxEtaVariationPr);
2503 etaCorrEl = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrEl - 1.0);
2504 etaCorrKa = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrKa - 1.0);
2505 etaCorrPi = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPi - 1.0);
2506 etaCorrMu = fTakeIntoAccountMuons ? (1.0 + usedSystematicScalingEtaCorrection * (etaCorrMu - 1.0)) : 1.0;
2507 etaCorrPr = 1.0 + usedSystematicScalingEtaCorrection * (etaCorrPr - 1.0);
2511 // Get the multiplicity correction factors for the (modified) expected dEdx
2512 const Int_t currEvtMultiplicity = fPIDResponse->GetTPCResponse().GetCurrentEventMultiplicity();
2514 Double_t multiplicityCorrEl = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2515 dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2516 Double_t multiplicityCorrKa = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2517 dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2518 Double_t multiplicityCorrPi = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2519 dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2520 Double_t multiplicityCorrMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2521 fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track, dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2522 Double_t multiplicityCorrPr = fPIDResponse->UseTPCMultiplicityCorrection() ? fPIDResponse->GetTPCResponse().GetMultiplicityCorrectionFast(track,
2523 dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2525 Double_t multiplicityCorrSigmaEl = fPIDResponse->UseTPCMultiplicityCorrection() ?
2526 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxEl * etaCorrEl, currEvtMultiplicity) : 1.;
2527 Double_t multiplicityCorrSigmaKa = fPIDResponse->UseTPCMultiplicityCorrection() ?
2528 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxKa * etaCorrKa, currEvtMultiplicity) : 1.;
2529 Double_t multiplicityCorrSigmaPi = fPIDResponse->UseTPCMultiplicityCorrection() ?
2530 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPi * etaCorrPi, currEvtMultiplicity) : 1.;
2531 Double_t multiplicityCorrSigmaMu = fTakeIntoAccountMuons && fPIDResponse->UseTPCMultiplicityCorrection() ?
2532 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxMu * etaCorrMu, currEvtMultiplicity) : 1.;
2533 Double_t multiplicityCorrSigmaPr = fPIDResponse->UseTPCMultiplicityCorrection() ?
2534 fPIDResponse->GetTPCResponse().GetMultiplicitySigmaCorrectionFast(dEdxPr * etaCorrPr, currEvtMultiplicity) : 1.;
2536 // Scale multiplicity correction factors, if desired (and multiplicity correction functions are to be used, otherwise it is not possible!)
2537 if (fPIDResponse->UseTPCMultiplicityCorrection() && TMath::Abs(fSystematicScalingMultCorrection - 1.0) > fgkEpsilon) {
2538 // Since we do not want to scale the splines with this, but only the multiplicity variation, only scale the deviation of the correction factor!
2539 // 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!
2541 multiplicityCorrEl = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrEl - 1.0);
2542 multiplicityCorrKa = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrKa - 1.0);
2543 multiplicityCorrPi = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPi - 1.0);
2544 multiplicityCorrMu = fTakeIntoAccountMuons ? (1.0 + fSystematicScalingMultCorrection * (multiplicityCorrMu - 1.0)) : 1.0;
2545 multiplicityCorrPr = 1.0 + fSystematicScalingMultCorrection * (multiplicityCorrPr - 1.0);
2548 // eta correction must be enabled in order to use the new sigma parametrisation maps. Since this is the absolute sigma
2549 // for a track calculated with the unscaled paramaters, we have to devide out dEdxExpectedEtaCorrected and then need
2550 // to scale with the multiplicitySigmaCorrFactor * fSystematicScalingEtaSigmaPara. In the end, one has to scale with the
2551 // (modified) dEdx to get the absolute sigma
2552 // This means there is no extra parameter for the multiplicitySigmaCorrFactor, but only for the sigma map itself.
2553 // This is valid, since it appears only as a product. One has to assume a larger systematic shift in case of additional
2554 // multiplicity dependence....
2556 Bool_t doSigmaSystematics = (TMath::Abs(fSystematicScalingEtaSigmaParaBelowThreshold - 1.0) > fgkEpsilon) ||
2557 (TMath::Abs(fSystematicScalingEtaSigmaParaAboveThreshold - 1.0) > fgkEpsilon);
2560 Double_t dEdxElExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2562 Double_t systematicScalingEtaSigmaParaEl = 1.;
2563 if (doSigmaSystematics) {
2564 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxElExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2565 systematicScalingEtaSigmaParaEl = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2566 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2568 Double_t sigmaRelEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2570 / dEdxElExpected * systematicScalingEtaSigmaParaEl * multiplicityCorrSigmaEl;
2573 Double_t dEdxKaExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2575 Double_t systematicScalingEtaSigmaParaKa = 1.;
2576 if (doSigmaSystematics) {
2577 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxKaExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2578 systematicScalingEtaSigmaParaKa = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2579 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2581 Double_t sigmaRelKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2583 / dEdxKaExpected * systematicScalingEtaSigmaParaKa * multiplicityCorrSigmaKa;
2586 Double_t dEdxPiExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2588 Double_t systematicScalingEtaSigmaParaPi = 1.;
2589 if (doSigmaSystematics) {
2590 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPiExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2591 systematicScalingEtaSigmaParaPi = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2592 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2594 Double_t sigmaRelPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2596 / dEdxPiExpected * systematicScalingEtaSigmaParaPi * multiplicityCorrSigmaPi;
2599 Double_t sigmaRelMu = 999.;
2600 if (fTakeIntoAccountMuons) {
2601 Double_t dEdxMuExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2603 Double_t systematicScalingEtaSigmaParaMu = 1.;
2604 if (doSigmaSystematics) {
2605 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxMuExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2606 systematicScalingEtaSigmaParaMu = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2607 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2609 sigmaRelMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault, kTRUE, kFALSE)
2610 / dEdxMuExpected * systematicScalingEtaSigmaParaMu * multiplicityCorrSigmaMu;
2614 Double_t dEdxPrExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2616 Double_t systematicScalingEtaSigmaParaPr = 1.;
2617 if (doSigmaSystematics) {
2618 Double_t scaleFactor = 0.5 * (1. + TMath::Erf((dEdxPrExpected - fSystematicScalingEtaSigmaParaThreshold) / 25.));
2619 systematicScalingEtaSigmaParaPr = fSystematicScalingEtaSigmaParaBelowThreshold * (1 - scaleFactor)
2620 + fSystematicScalingEtaSigmaParaAboveThreshold * scaleFactor;
2622 Double_t sigmaRelPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2624 / dEdxPrExpected * systematicScalingEtaSigmaParaPr * multiplicityCorrSigmaPr;
2626 // Now scale the (possibly modified) spline values with the (possibly modified) correction factors
2627 dEdxEl *= etaCorrEl * multiplicityCorrEl;
2628 dEdxKa *= etaCorrKa * multiplicityCorrKa;
2629 dEdxPi *= etaCorrPi * multiplicityCorrPi;
2630 dEdxMu *= etaCorrMu * multiplicityCorrMu;
2631 dEdxPr *= etaCorrPr * multiplicityCorrPr;
2633 // Finally, get the absolute sigma
2634 sigmaEl = sigmaRelEl * dEdxEl;
2635 sigmaKa = sigmaRelKa * dEdxKa;
2636 sigmaPi = sigmaRelPi * dEdxPi;
2637 sigmaMu = sigmaRelMu * dEdxMu;
2638 sigmaPr = sigmaRelPr * dEdxPr;
2642 // No systematic studies on expected signal - just take it as it comes from the TPCPIDResponse
2643 dEdxEl = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2644 fPIDResponse->UseTPCEtaCorrection(),
2645 fPIDResponse->UseTPCMultiplicityCorrection());
2646 dEdxKa = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2647 fPIDResponse->UseTPCEtaCorrection(),
2648 fPIDResponse->UseTPCMultiplicityCorrection());
2649 dEdxPi = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2650 fPIDResponse->UseTPCEtaCorrection(),
2651 fPIDResponse->UseTPCMultiplicityCorrection());
2652 dEdxMu = !fTakeIntoAccountMuons ? -1 :
2653 fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2654 fPIDResponse->UseTPCEtaCorrection(),
2655 fPIDResponse->UseTPCMultiplicityCorrection());
2656 dEdxPr = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2657 fPIDResponse->UseTPCEtaCorrection(),
2658 fPIDResponse->UseTPCMultiplicityCorrection());
2660 sigmaEl = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kElectron, AliTPCPIDResponse::kdEdxDefault,
2661 fPIDResponse->UseTPCEtaCorrection(),
2662 fPIDResponse->UseTPCMultiplicityCorrection());
2663 sigmaKa = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kKaon, AliTPCPIDResponse::kdEdxDefault,
2664 fPIDResponse->UseTPCEtaCorrection(),
2665 fPIDResponse->UseTPCMultiplicityCorrection());
2666 sigmaPi = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
2667 fPIDResponse->UseTPCEtaCorrection(),
2668 fPIDResponse->UseTPCMultiplicityCorrection());
2669 sigmaMu = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kMuon, AliTPCPIDResponse::kdEdxDefault,
2670 fPIDResponse->UseTPCEtaCorrection(),
2671 fPIDResponse->UseTPCMultiplicityCorrection());
2672 sigmaPr = fPIDResponse->GetTPCResponse().GetExpectedSigma(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
2673 fPIDResponse->UseTPCEtaCorrection(),
2674 fPIDResponse->UseTPCMultiplicityCorrection());
2677 Double_t deltaPrimeElectron = (dEdxEl > 0) ? dEdxTPC / dEdxEl : -1;
2679 Printf("Error: Expected TPC signal <= 0 for electron hypothesis");
2683 Double_t deltaPrimeKaon = (dEdxKa > 0) ? dEdxTPC / dEdxKa : -1;
2685 Printf("Error: Expected TPC signal <= 0 for kaon hypothesis");
2689 Double_t deltaPrimePion = (dEdxPi > 0) ? dEdxTPC / dEdxPi : -1;
2691 Printf("Error: Expected TPC signal <= 0 for pion hypothesis");
2695 Double_t deltaPrimeProton = (dEdxPr > 0) ? dEdxTPC / dEdxPr : -1;
2697 Printf("Error: Expected TPC signal <= 0 for proton hypothesis");
2702 printf("File: %s, Line: %d: ProcessTrack -> Compute probabilities\n", (char*)__FILE__, __LINE__);
2705 // Use probabilities to weigh the response generation for the different species.
2706 // Also determine the most probable particle type.
2707 Double_t prob[AliPID::kSPECIESC];
2708 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2711 fPIDcombined->ComputeProbabilities(track, fPIDResponse, prob);
2713 // If muons are not to be taken into account, just set their probability to zero and normalise the remaining probabilities later
2714 if (!fTakeIntoAccountMuons)
2715 prob[AliPID::kMuon] = 0;
2717 // Priors might cause problems in case of mismatches, i.e. mismatch particles will be identified as pions.
2718 // Can be easily caught for low p_TPC by just setting pion (and muon) probs to zero, if dEdx is larger than
2719 // expected dEdx of electrons and kaons
2720 if (pTPC < 1. && dEdxTPC > dEdxEl && dEdxTPC > dEdxKa) {
2721 prob[AliPID::kMuon] = 0;
2722 prob[AliPID::kPion] = 0;
2726 // Bug: One can set the number of species for PIDcombined, but PIDcombined will call PIDresponse, which writes without testing
2727 // the probs for kSPECIESC (including light nuclei) into the array.
2728 // In this case, when only kSPECIES are considered, the probabilities have to be rescaled!
2731 // 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
2732 // high-pT region (also contribution there completely negligable!)
2733 // 2. If dEdx is larger than the expected dEdx + 5 sigma of el and pr, it is most likely a light nucleus
2734 // (if dEdx is more than 5 sigma away from expectation, flat TPC probs are set... and the light nuclei splines are not
2737 // The highest expected dEdx is either for pr or for el. Assign 100% probability to the species with highest expected dEdx then.
2738 // In all other cases: Throw away light nuclei probs and rescale other probs to 100%.
2740 // Find most probable species for the ID
2741 Int_t maxIndex = TMath::LocMax(AliPID::kSPECIESC, prob);
2743 if ((prob[maxIndex] > 0 && maxIndex >= AliPID::kSPECIES && dEdxTPC > dEdxEl + 5. * sigmaEl) ||
2744 (dEdxTPC > dEdxEl + 5. * sigmaEl && dEdxTPC > dEdxPr + 5. * sigmaPr)) {
2745 for (Int_t i = 0; i < AliPID::kSPECIESC; i++)
2748 if (dEdxEl > dEdxPr) {
2749 prob[AliPID::kElectron] = 1.;
2750 maxIndex = AliPID::kElectron;
2753 prob[AliPID::kProton] = 1.;
2754 maxIndex = AliPID::kProton;
2758 for (Int_t i = AliPID::kSPECIES; i < AliPID::kSPECIESC; i++)
2761 Double_t probSum = 0.;
2762 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2766 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2770 // If all probabilities are equal (should only happen if no priors are used), set most probable PID to pion
2771 // because LocMax returns just the first maximal value (i.e. AliPID::kElectron)
2772 if (TMath::Abs(prob[maxIndex] - 1. / AliPID::kSPECIES) < 1e-5)
2773 maxIndex = AliPID::kPion;
2775 // In all other cases, the maximum remains untouched from the scaling (and is < AliPID::kSPECIES by construction)
2779 // Generate the expected responses in DeltaPrime and translate to real dEdx. Only take responses for exactly that species
2780 // (i.e. with pre-PID)
2782 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
2784 ErrorCode errCode = kNoErrors;
2787 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check\n", (char*)__FILE__, __LINE__);
2790 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
2793 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
2796 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
2799 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
2801 if (errCode == kNoErrors) {
2802 Double_t genEntry[kDeDxCheckNumAxes];
2803 genEntry[kDeDxCheckJetPt] = jetPt;
2804 genEntry[kDeDxCheckEtaAbs] = TMath::Abs(track->Eta());
2805 genEntry[kDeDxCheckP] = pTPC;
2808 for (Int_t n = 0; n < numGenEntries; n++) {
2809 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
2810 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
2812 // Consider generated response as originating from...
2813 if (rnd <= prob[AliPID::kElectron]) {
2814 genEntry[kDeDxCheckPID] = 0; // ... an electron
2815 genEntry[kDeDxCheckDeDx] = fGenRespElDeltaPrimeEl[n] * dEdxEl;
2817 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon]) {
2818 genEntry[kDeDxCheckPID] = 1; // ... a kaon
2819 genEntry[kDeDxCheckDeDx] = fGenRespKaDeltaPrimeKa[n] * dEdxKa;
2821 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion]) {
2822 genEntry[kDeDxCheckPID] = 2; // ... a pion (or a muon)
2823 genEntry[kDeDxCheckDeDx] = fGenRespPiDeltaPrimePi[n] * dEdxPi;
2826 genEntry[kDeDxCheckPID] = 3; // ... a proton
2827 genEntry[kDeDxCheckDeDx] = fGenRespPrDeltaPrimePr[n] * dEdxPr;
2830 fDeDxCheck->Fill(genEntry);
2835 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses for dEdx check done\n", (char*)__FILE__, __LINE__);
2838 if (fDoPtResolution) {
2839 // Check shared clusters, which is done together with the pT resolution
2840 Double_t qaEntry[kQASharedClsNumAxes];
2841 qaEntry[kQASharedClsJetPt] = jetPt;
2842 qaEntry[kQASharedClsPt] = pT;
2843 qaEntry[kDeDxCheckP] = pTPC;
2844 qaEntry[kQASharedClsNumSharedCls] = track->GetTPCSharedMapPtr()->CountBits();
2847 // iRowInd == -1 for "all rows w/o multiple counting"
2848 qaEntry[kQASharedClsPadRow] = iRowInd;
2849 fQASharedCls->Fill(qaEntry);
2851 // Fill hist for every pad row with shared cluster
2852 for (iRowInd = 0; iRowInd < 159; iRowInd++) {
2853 if (track->GetTPCSharedMapPtr()->TestBitNumber(iRowInd)) {
2854 qaEntry[kQASharedClsPadRow] = iRowInd;
2855 fQASharedCls->Fill(qaEntry);
2864 // Clean up the most probable PID for low momenta (not an issue for the probabilities, since fractions small,
2865 // but to get clean (and nice looking) templates (if most probable PID is used instead of generated responses), it should be done).
2866 // Problem: If more than 5 sigma away (and since priors also included), most probable PID for dEdx around protons could be pions.
2867 // Idea: Only clean selection for K and p possible. So, just take for the most probable PID the probs from TPC only calculated
2868 // by hand without restriction to 5 sigma and without priors. This will not affect the template generation, but afterwards one
2869 // can replace the K and p templates with the most probable PID distributions, so all other species templates remain the same.
2870 // I.e. it doesn't hurt if the most probable PID is distributed incorrectly between el, pi, mu.
2871 Bool_t maxIndexSetManually = kFALSE;
2874 Double_t probManualTPC[AliPID::kSPECIES];
2875 for (Int_t i = 0; i < AliPID::kSPECIES; i++)
2876 probManualTPC[i] = 0;
2878 probManualTPC[AliPID::kElectron] = TMath::Exp(-0.5*(dEdxTPC-dEdxEl)*(dEdxTPC-dEdxEl)/(sigmaEl*sigmaEl))/sigmaEl;
2879 // Muons are not important here, just ignore and save processing time
2880 probManualTPC[AliPID::kMuon] = 0.;//TMath::Exp(-0.5*(dEdxTPC-dEdxMu)*(dEdxTPC-dEdxMu)/(sigmaMu*sigmaMu))/sigmaMu;
2881 probManualTPC[AliPID::kPion] = TMath::Exp(-0.5*(dEdxTPC-dEdxPi)*(dEdxTPC-dEdxPi)/(sigmaPi*sigmaPi))/sigmaPi;
2882 probManualTPC[AliPID::kKaon] = TMath::Exp(-0.5*(dEdxTPC-dEdxKa)*(dEdxTPC-dEdxKa)/(sigmaKa*sigmaKa))/sigmaKa;
2883 probManualTPC[AliPID::kProton] = TMath::Exp(-0.5*(dEdxTPC-dEdxPr)*(dEdxTPC-dEdxPr)/(sigmaPr*sigmaPr))/sigmaPr;
2885 const Int_t maxIndexManualTPC = TMath::LocMax(AliPID::kSPECIES, probManualTPC);
2886 // Should always be > 0, but in case the dEdx is far off such that the machine accuracy sets every prob to zero,
2887 // better take the "old" result
2888 if (probManualTPC[maxIndexManualTPC] > 0.)
2889 maxIndex = maxIndexManualTPC;
2891 maxIndexSetManually = kTRUE;
2895 // Translate from AliPID numbering to numbering of this class
2896 if (prob[maxIndex] > 0 || maxIndexSetManually) {
2897 if (maxIndex == AliPID::kElectron)
2899 else if (maxIndex == AliPID::kKaon)
2901 else if (maxIndex == AliPID::kMuon)
2903 else if (maxIndex == AliPID::kPion)
2905 else if (maxIndex == AliPID::kProton)
2911 // Only take track into account for expectation values, if valid pid response is available.. Otherwise: Set to underflow bin.
2917 //For testing: Swap p<->pT to analyse pure p-dependence => Needs to be removed later
2923 TOFpidInfo tofPIDinfo = GetTOFType(track, fTOFmode);
2925 Double_t entry[fStoreAdditionalJetInformation ? kDataNumAxes : kDataNumAxes - fgkNumJetAxes];
2926 entry[kDataMCID] = binMC;
2927 entry[kDataSelectSpecies] = 0;
2928 entry[kDataPt] = pT;
2929 entry[kDataDeltaPrimeSpecies] = deltaPrimeElectron;
2930 entry[kDataCentrality] = centralityPercentile;
2932 if (fStoreAdditionalJetInformation) {
2933 entry[kDataJetPt] = jetPt;
2935 entry[kDataXi] = xi;
2938 entry[GetIndexOfChargeAxisData()] = trackCharge;
2939 entry[GetIndexOfTOFpidInfoAxisData()] = tofPIDinfo;
2941 fhPIDdataAll->Fill(entry);
2943 entry[kDataSelectSpecies] = 1;
2944 entry[kDataDeltaPrimeSpecies] = deltaPrimeKaon;
2945 fhPIDdataAll->Fill(entry);
2947 entry[kDataSelectSpecies] = 2;
2948 entry[kDataDeltaPrimeSpecies] = deltaPrimePion;
2949 fhPIDdataAll->Fill(entry);
2951 entry[kDataSelectSpecies] = 3;
2952 entry[kDataDeltaPrimeSpecies] = deltaPrimeProton;
2953 fhPIDdataAll->Fill(entry);
2956 // Construct the expected shape for the transition p -> pT
2958 Double_t genEntry[fStoreAdditionalJetInformation ? kGenNumAxes : kGenNumAxes - fgkNumJetAxes];
2959 genEntry[kGenMCID] = binMC;
2960 genEntry[kGenSelectSpecies] = 0;
2961 genEntry[kGenPt] = pT;
2962 genEntry[kGenDeltaPrimeSpecies] = -999;
2963 genEntry[kGenCentrality] = centralityPercentile;
2965 if (fStoreAdditionalJetInformation) {
2966 genEntry[kGenJetPt] = jetPt;
2967 genEntry[kGenZ] = z;
2968 genEntry[kGenXi] = xi;
2971 genEntry[GetIndexOfChargeAxisGen()] = trackCharge;
2972 genEntry[GetIndexOfTOFpidInfoAxisGen()] = tofPIDinfo;
2974 // Generate numGenEntries "responses" with fluctuations around the expected values.
2975 // fgkMaxNumGenEntries = 500 turned out to give reasonable templates even for highest track pT in 15-20 GeV/c jet pT bin.
2976 Int_t numGenEntries = fgkMaxNumGenEntries; // fgkMaxNumGenEntries = 500
2978 /*OLD: Different number of responses depending on pT and jet pT for fgkMaxNumGenEntries = 1000
2979 * => Problem: If threshold to higher number of responses inside a bin (or after rebinning), then the template
2980 * is biased to the higher pT.
2981 // Generate numGenEntries "responses" with fluctuations around the expected values.
2982 // The higher the (transverse) momentum, the more "responses" will be generated in order not to run out of statistics too fast.
2983 Int_t numGenEntries = 10;
2985 // Jets have even worse statistics, therefore, scale numGenEntries further
2987 numGenEntries *= 20;
2988 else if (jetPt >= 20)
2989 numGenEntries *= 10;
2990 else if (jetPt >= 10)
2995 // Do not generate more entries than available in memory!
2996 if (numGenEntries > fgkMaxNumGenEntries)// fgkMaxNumGenEntries = 1000
2997 numGenEntries = fgkMaxNumGenEntries;
3001 ErrorCode errCode = kNoErrors;
3004 printf("File: %s, Line: %d: ProcessTrack -> Generate Responses\n", (char*)__FILE__, __LINE__);
3007 errCode = GenerateDetectorResponse(errCode, 1., sigmaEl / dEdxEl, fGenRespElDeltaPrimeEl, numGenEntries);
3008 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxKa, sigmaEl / dEdxKa, fGenRespElDeltaPrimeKa, numGenEntries);
3009 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPi, sigmaEl / dEdxPi, fGenRespElDeltaPrimePi, numGenEntries);
3010 errCode = GenerateDetectorResponse(errCode, dEdxEl / dEdxPr, sigmaEl / dEdxPr, fGenRespElDeltaPrimePr, numGenEntries);
3013 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxEl, sigmaKa / dEdxEl, fGenRespKaDeltaPrimeEl, numGenEntries);
3014 errCode = GenerateDetectorResponse(errCode, 1., sigmaKa / dEdxKa, fGenRespKaDeltaPrimeKa, numGenEntries);
3015 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPi, sigmaKa / dEdxPi, fGenRespKaDeltaPrimePi, numGenEntries);
3016 errCode = GenerateDetectorResponse(errCode, dEdxKa / dEdxPr, sigmaKa / dEdxPr, fGenRespKaDeltaPrimePr, numGenEntries);
3019 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxEl, sigmaPi / dEdxEl, fGenRespPiDeltaPrimeEl, numGenEntries);
3020 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxKa, sigmaPi / dEdxKa, fGenRespPiDeltaPrimeKa, numGenEntries);
3021 errCode = GenerateDetectorResponse(errCode, 1., sigmaPi / dEdxPi, fGenRespPiDeltaPrimePi, numGenEntries);
3022 errCode = GenerateDetectorResponse(errCode, dEdxPi / dEdxPr, sigmaPi / dEdxPr, fGenRespPiDeltaPrimePr, numGenEntries);
3024 // Muons, if desired
3025 if (fTakeIntoAccountMuons) {
3026 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxEl, sigmaMu / dEdxEl, fGenRespMuDeltaPrimeEl, numGenEntries);
3027 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxKa, sigmaMu / dEdxKa, fGenRespMuDeltaPrimeKa, numGenEntries);
3028 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPi, sigmaMu / dEdxPi, fGenRespMuDeltaPrimePi, numGenEntries);
3029 errCode = GenerateDetectorResponse(errCode, dEdxMu / dEdxPr, sigmaMu / dEdxPr, fGenRespMuDeltaPrimePr, numGenEntries);
3033 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxEl, sigmaPr / dEdxEl, fGenRespPrDeltaPrimeEl, numGenEntries);
3034 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxKa, sigmaPr / dEdxKa, fGenRespPrDeltaPrimeKa, numGenEntries);
3035 errCode = GenerateDetectorResponse(errCode, dEdxPr / dEdxPi, sigmaPr / dEdxPi, fGenRespPrDeltaPrimePi, numGenEntries);
3036 errCode = GenerateDetectorResponse(errCode, 1., sigmaPr / dEdxPr, fGenRespPrDeltaPrimePr, numGenEntries);
3038 if (errCode != kNoErrors) {
3039 if (errCode == kWarning && fDebug > 1) {
3040 Printf("Warning: Questionable detector response for track, most likely due to very low number of PID clusters! Debug output (dEdx_expected, sigma_expected):");
3043 Printf("Error: Failed to generate detector response for track - skipped! Debug output (dEdx_expected, sigma_expected):");
3046 Printf("Pr: %e, %e", dEdxPr, sigmaPr);
3047 Printf("Pi: %e, %e", dEdxPi, sigmaPi);
3048 Printf("El: %e, %e", dEdxEl, sigmaEl);
3049 Printf("Mu: %e, %e", dEdxMu, sigmaMu);
3050 Printf("Ka: %e, %e", dEdxKa, sigmaKa);
3051 Printf("track: dEdx %f, pTPC %f, eta %f, ncl %d\n", track->GetTPCsignal(), track->GetTPCmomentum(), track->Eta(),
3052 track->GetTPCsignalN());
3055 if (errCode != kWarning) {
3056 return kFALSE;// Skip generated response in case of error
3060 for (Int_t n = 0; n < numGenEntries; n++) {
3061 if (!isMC || !fUseMCidForGeneration) {
3062 // If no MC info is available or shall not be used, use weighting with priors to generate entries for the different species
3063 Double_t rnd = fRandom->Rndm(); // Produce uniformly distributed floating point in ]0, 1]
3065 // Consider generated response as originating from...
3066 if (rnd <= prob[AliPID::kElectron])
3067 genEntry[kGenMCID] = 0; // ... an electron
3068 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon])
3069 genEntry[kGenMCID] = 1; // ... a kaon
3070 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon])
3071 genEntry[kGenMCID] = 2; // ... a muon -> NOTE: prob[AliPID::kMuon] = 0 in case of fTakeIntoAccountMuons = kFALSE
3072 else if (rnd <= prob[AliPID::kElectron] + prob[AliPID::kKaon] + prob[AliPID::kMuon] + prob[AliPID::kPion])
3073 genEntry[kGenMCID] = 3; // ... a pion
3075 genEntry[kGenMCID] = 4; // ... a proton
3079 genEntry[kGenSelectSpecies] = 0;
3080 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeEl[n];
3081 fhGenEl->Fill(genEntry);
3083 genEntry[kGenSelectSpecies] = 1;
3084 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimeKa[n];
3085 fhGenEl->Fill(genEntry);
3087 genEntry[kGenSelectSpecies] = 2;
3088 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePi[n];
3089 fhGenEl->Fill(genEntry);
3091 genEntry[kGenSelectSpecies] = 3;
3092 genEntry[kGenDeltaPrimeSpecies] = fGenRespElDeltaPrimePr[n];
3093 fhGenEl->Fill(genEntry);
3096 genEntry[kGenSelectSpecies] = 0;
3097 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeEl[n];
3098 fhGenKa->Fill(genEntry);
3100 genEntry[kGenSelectSpecies] = 1;
3101 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimeKa[n];
3102 fhGenKa->Fill(genEntry);
3104 genEntry[kGenSelectSpecies] = 2;
3105 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePi[n];
3106 fhGenKa->Fill(genEntry);
3108 genEntry[kGenSelectSpecies] = 3;
3109 genEntry[kGenDeltaPrimeSpecies] = fGenRespKaDeltaPrimePr[n];
3110 fhGenKa->Fill(genEntry);
3113 genEntry[kGenSelectSpecies] = 0;
3114 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeEl[n];
3115 fhGenPi->Fill(genEntry);
3117 genEntry[kGenSelectSpecies] = 1;
3118 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimeKa[n];
3119 fhGenPi->Fill(genEntry);
3121 genEntry[kGenSelectSpecies] = 2;
3122 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePi[n];
3123 fhGenPi->Fill(genEntry);
3125 genEntry[kGenSelectSpecies] = 3;
3126 genEntry[kGenDeltaPrimeSpecies] = fGenRespPiDeltaPrimePr[n];
3127 fhGenPi->Fill(genEntry);
3129 if (fTakeIntoAccountMuons) {
3130 // Muons, if desired
3131 genEntry[kGenSelectSpecies] = 0;
3132 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeEl[n];
3133 fhGenMu->Fill(genEntry);
3135 genEntry[kGenSelectSpecies] = 1;
3136 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimeKa[n];
3137 fhGenMu->Fill(genEntry);
3139 genEntry[kGenSelectSpecies] = 2;
3140 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePi[n];
3141 fhGenMu->Fill(genEntry);
3143 genEntry[kGenSelectSpecies] = 3;
3144 genEntry[kGenDeltaPrimeSpecies] = fGenRespMuDeltaPrimePr[n];
3145 fhGenMu->Fill(genEntry);
3149 genEntry[kGenSelectSpecies] = 0;
3150 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeEl[n];
3151 fhGenPr->Fill(genEntry);
3153 genEntry[kGenSelectSpecies] = 1;
3154 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimeKa[n];
3155 fhGenPr->Fill(genEntry);
3157 genEntry[kGenSelectSpecies] = 2;
3158 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePi[n];
3159 fhGenPr->Fill(genEntry);
3161 genEntry[kGenSelectSpecies] = 3;
3162 genEntry[kGenDeltaPrimeSpecies] = fGenRespPrDeltaPrimePr[n];
3163 fhGenPr->Fill(genEntry);
3167 printf("File: %s, Line: %d: ProcessTrack -> Done\n", (char*)__FILE__, __LINE__);
3173 //_____________________________________________________________________________
3174 Bool_t AliAnalysisTaskPID::SetConvolutedGaussLambdaParameter(Double_t lambda)
3176 // Set the lambda parameter of the convolution to the desired value. Automatically
3177 // calculates the parameters for the transition (restricted) gauss -> convoluted gauss.
3178 fConvolutedGaussTransitionPars[2] = lambda;
3180 // Save old parameters and settings of function to restore them later:
3181 Double_t* oldFuncParams = new Double_t[fkConvolutedGausNPar];
3182 for (Int_t i = 0; i < fkConvolutedGausNPar; i++)
3183 oldFuncParams[i] = fConvolutedGausDeltaPrime->GetParameter(i);
3184 Int_t oldFuncNpx = fConvolutedGausDeltaPrime->GetNpx();
3185 Double_t oldFuncRangeLow = 0, oldFuncRangeUp = 100;
3186 fConvolutedGausDeltaPrime->GetRange(oldFuncRangeLow, oldFuncRangeUp);
3188 // Choose some sufficiently large range
3189 const Double_t rangeStart = 0.5;
3190 const Double_t rangeEnd = 2.0;
3192 // To get the parameters for the transition, just choose arbitrarily input parameters for mu and sigma
3193 // (it makes sense to choose typical values). The ratio sigma_gauss / sigma_convolution is independent
3194 // of mu and as well the difference mu_gauss - mu_convolution.
3195 Double_t muInput = 1.0;
3196 Double_t sigmaInput = fgkSigmaReferenceForTransitionPars;
3199 // Step 1: Generate distribution with input parameters
3200 const Int_t nPar = 3;
3201 Double_t inputPar[nPar] = { muInput, sigmaInput, lambda };
3203 TH1D* hInput = new TH1D("hInput", "Input distribution", 2000, rangeStart, rangeEnd);
3205 fConvolutedGausDeltaPrime->SetParameters(inputPar);
3206 fConvolutedGausDeltaPrime->SetRange(rangeStart, rangeEnd);
3207 fConvolutedGausDeltaPrime->SetNpx(2000);
3210 // The resolution and mean of the AliPIDResponse are determined in finite intervals
3211 // of ncl (also second order effects due to finite dEdx and tanTheta).
3212 // Take this into account for the transition parameters via assuming an approximately flat
3213 // distritubtion in ncl in this interval.
3214 // NOTE: The ncl interval should be the same as the one used for the sigma map creation!
3215 const Int_t nclStart = 151;
3216 const Int_t nclEnd = 160;
3217 const Int_t nclSteps = (nclEnd - nclStart) + 1;
3218 for (Int_t ncl = nclStart; ncl <= nclEnd; ncl++) {
3219 // Resolution scales with 1/sqrt(ncl)
3220 fConvolutedGausDeltaPrime->SetParameter(1, inputPar[1] * sqrt(nclEnd) / sqrt(ncl));
3221 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3223 for (Int_t i = 0; i < 50000000 / nclSteps; i++)
3224 hInput->Fill(hProbDensity->GetRandom());
3228 TH1* hProbDensity = fConvolutedGausDeltaPrime->GetHistogram();
3230 for (Int_t i = 0; i < 50000000; i++)
3231 hInput->Fill(hProbDensity->GetRandom());
3233 // Step 2: Fit generated distribution with restricted gaussian
3234 Int_t maxBin = hInput->GetMaximumBin();
3235 Double_t max = hInput->GetBinContent(maxBin);
3237 UChar_t usedBins = 1;
3239 max += hInput->GetBinContent(maxBin - 1);
3242 if (maxBin < hInput->GetNbinsX()) {
3243 max += hInput->GetBinContent(maxBin + 1);
3248 // NOTE: The range (<-> fraction of maximum) should be the same
3249 // as for the spline and eta maps creation
3250 const Double_t lowThreshold = hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max));
3251 const Double_t highThreshold = hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max));
3253 TFitResultPtr fitResGaussFirstStep = hInput->Fit("gaus", "QNRS", "", lowThreshold, highThreshold);
3255 TFitResultPtr fitResGauss;
3257 if ((Int_t)fitResGaussFirstStep == 0) {
3258 TF1 fGauss("fGauss", "[0]*TMath::Gaus(x, [1], [2], 1)", rangeStart, rangeEnd);
3259 fGauss.SetParameter(0, fitResGaussFirstStep->GetParams()[0]);
3260 fGauss.SetParError(0, fitResGaussFirstStep->GetErrors()[0]);
3261 fGauss.SetParameter(2, fitResGaussFirstStep->GetParams()[2]);
3262 fGauss.SetParError(2, fitResGaussFirstStep->GetErrors()[2]);
3264 fGauss.FixParameter(1, fitResGaussFirstStep->GetParams()[1]);
3265 fitResGauss = hInput->Fit(&fGauss, "QNS", "s", rangeStart, rangeEnd);
3268 fitResGauss = hInput->Fit("gaus", "QNRS", "same", rangeStart, rangeEnd);
3270 //OLD TFitResultPtr fitResGauss = hInput->Fit("gaus", "QNRS", "", hInput->GetXaxis()->GetBinLowEdge(hInput->FindFirstBinAbove(0.1 * max)),
3271 // hInput->GetXaxis()->GetBinUpEdge(hInput->FindLastBinAbove(0.1 * max)));
3274 // Step 3: Use parameters from gaussian fit to obtain parameters for the transition "restricted gauss" -> "convoluted gauss"
3276 // 3.1 The ratio sigmaInput / sigma_gaussFit ONLY depends on lambda (which is fixed per period) -> Calculate this first
3277 // for an arbitrary (here: typical) sigma. The ratio is then ~the same for ALL sigma for given lambda!
3278 if ((Int_t)fitResGauss != 0) {
3279 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Gauss Fit failed!\n");
3280 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3281 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3282 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3285 delete [] oldFuncParams;
3290 if (fitResGauss->GetParams()[2] <= 0) {
3291 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Sigma of gauss fit <= 0!\n");
3292 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3293 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3294 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3297 delete [] oldFuncParams;
3302 // sigma correction factor
3303 fConvolutedGaussTransitionPars[1] = sigmaInput / fitResGauss->GetParams()[2];
3305 // 3.2 Now that sigma und lambda are determined, one can calculate mu by shifting the maximum to the desired position,
3306 // i.e. the maximum of the input distribution should coincide with that of the re-calculated distribution,
3307 // which is achieved by getting the same mu for the same sigma.
3308 // NOTE: For fixed lambda, the shift is proportional to sigma and independent of mu!
3309 // So, one can calculate the shift for an arbitrary fixed (here: typical)
3310 // sigma and then simply use this shift for any other sigma by scaling it correspondingly!!!
3312 // Mu shift correction:
3313 // Shift in mu (difference between mean of gauss and mean of convolution) is proportional to sigma!
3314 // Thus, choose a reference sigma (typical -> 0.05), such that for arbitrary sigma one can simple scale
3315 // this shift correction with sigma / referenceSigma.
3316 fConvolutedGaussTransitionPars[0] = (fitResGauss->GetParams()[1] - muInput);
3319 /*Changed on 03.07.2013
3321 // Maximum of fConvolutedGausDeltaPrime should agree with maximum of input
3322 Double_t par[nPar] = { fitResGauss->GetParams()[1], // just as a guess of the maximum position
3326 fConvolutedGausDeltaPrime->SetParameters(par);
3328 Double_t maxXInput = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, muInput - 3. * sigmaInput),
3329 muInput + 10. * sigmaInput,
3332 // Maximum shifts proportional to sigma and is linear in mu (~mean of gauss)
3333 // Maximum should be typically located within [gaussMean, gaussMean + 3 gaussSigma].
3334 // -> Larger search range for safety reasons (also: sigma and/or mean might be not 100% accurate).
3335 Double_t maxXconvoluted = fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001,
3336 fitResGauss->GetParams()[1] - 3. * fitResGauss->GetParams()[2]),
3337 fitResGauss->GetParams()[1] + 10. * fitResGauss->GetParams()[2],
3339 if (maxXconvoluted <= 0) {
3340 AliError("Not able to calculate parameters for the transition \"restricted gauss\" -> \"convoluted gauss\": Maximum of fConvolutedGausDeltaPrime <= 0!\n");
3342 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3343 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3344 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3347 delete [] oldFuncParams;
3352 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX to input value.
3353 // Mu shift correction:
3354 fConvolutedGaussTransitionPars[0] = maxXconvoluted - maxXInput;
3359 fConvolutedGausDeltaPrime->SetParameters(oldFuncParams);
3360 fConvolutedGausDeltaPrime->SetNpx(oldFuncNpx);
3361 fConvolutedGausDeltaPrime->SetRange(oldFuncRangeLow, oldFuncRangeUp);
3364 delete [] oldFuncParams;
3370 //_____________________________________________________________________________
3371 AliAnalysisTaskPID::ErrorCode AliAnalysisTaskPID::SetParamsForConvolutedGaus(Double_t gausMean, Double_t gausSigma)
3373 // Set parameters for convoluted gauss using parameters for a pure gaussian.
3374 // If SetConvolutedGaussLambdaParameter has not been called before to initialise the translation parameters,
3375 // some default parameters will be used and an error will show up.
3378 printf("File: %s, Line: %d: SetParamsForConvolutedGaus: mean %e, sigma %e\n", (char*)__FILE__, __LINE__, gausMean, gausSigma);
3380 if (fConvolutedGaussTransitionPars[1] < -998) {
3381 AliError("Transition parameters not initialised! Default parameters will be used. Please call SetConvolutedGaussLambdaParameter(...) before any calculations!");
3382 SetConvolutedGaussLambdaParameter(2.0);
3383 AliError(Form("Parameters set to:\n[0]: %f\n[1]: %f\n[2]: %f\n", fConvolutedGaussTransitionPars[0],
3384 fConvolutedGaussTransitionPars[1], fConvolutedGaussTransitionPars[2]));
3387 Double_t par[fkConvolutedGausNPar];
3388 par[2] = fConvolutedGaussTransitionPars[2];
3389 par[1] = fConvolutedGaussTransitionPars[1] * gausSigma;
3390 // maxX perfectly shifts as par[0] (scaled by sigma) -> Can shift maxX so that it sits at the right place.
3391 par[0] = gausMean - fConvolutedGaussTransitionPars[0] * par[1] / fgkSigmaReferenceForTransitionPars;
3393 ErrorCode errCode = kNoErrors;
3394 fConvolutedGausDeltaPrime->SetParameters(par);
3397 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> Parameters set to: %e, %e, %e (transition pars: %e, %e, %e, %e)\n",
3398 (char*)__FILE__, __LINE__, par[0], par[1], par[2], fConvolutedGaussTransitionPars[0], fConvolutedGaussTransitionPars[1],
3399 fConvolutedGaussTransitionPars[2], fgkSigmaReferenceForTransitionPars);
3401 fConvolutedGausDeltaPrime->SetNpx(20); // Small value speeds up following algorithm (valid, since extrema far apart)
3403 // Accuracy of 10^-5 is enough to get 0.1% precise peak for MIPS w.r.t. to dEdx = 2000 of protons
3404 // (should boost up the algorithm, because 10^-10 is the default value!)
3405 Double_t maxX= fConvolutedGausDeltaPrime->GetMaximumX(TMath::Max(0.001, gausMean - 2. * gausSigma),
3406 gausMean + 6. * gausSigma, 1.0E-5);
3408 const Double_t maximum = fConvolutedGausDeltaPrime->Eval(maxX);
3409 const Double_t maximumFraction = maximum * fAccuracyNonGaussianTail;
3411 // Estimate lower boundary for subsequent search:
3412 Double_t lowBoundSearchBoundLow = TMath::Max(1e-4, maxX - 5. * gausSigma);
3413 Double_t lowBoundSearchBoundUp = maxX;
3415 Bool_t lowerBoundaryFixedAtZero = kFALSE;
3417 while (fConvolutedGausDeltaPrime->Eval(lowBoundSearchBoundLow) >= maximumFraction) {
3418 if (lowBoundSearchBoundLow <= 0) {
3419 // This should only happen to low dEdx particles with very few clusters and therefore large sigma, such that the gauss goes below zero deltaPrime
3420 if (maximum <= 0) { // Something is weired
3421 printf("Error generating signal: maximum is <= 0!\n");
3425 const Double_t valueAtZero = fConvolutedGausDeltaPrime->Eval(0);
3426 if (valueAtZero / maximum > 0.05) {
3427 // Too large fraction below zero deltaPrime. Signal generation cannot be reliable in this case
3428 printf("Error generating signal: Too large fraction below zero deltaPrime: convGauss(0) / convGauss(max) = %e / %e = %e!\n",
3429 valueAtZero, maximum, valueAtZero / maximum);
3435 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",
3436 fConvolutedGausDeltaPrime->Eval(maxX), fAccuracyNonGaussianTail, maximumFraction, maxX, par[0], par[1], par[2], gausMean, gausSigma);
3439 lowerBoundaryFixedAtZero = kTRUE;
3441 if (errCode != kError)
3447 lowBoundSearchBoundUp -= gausSigma;
3448 lowBoundSearchBoundLow -= gausSigma;
3450 if (lowBoundSearchBoundLow < 0) {
3451 lowBoundSearchBoundLow = 0;
3452 lowBoundSearchBoundUp += gausSigma;
3456 // Determine lower boundary inside estimated range. For small values of the maximum: Need more precision, since finer binning!
3457 Double_t rangeStart = lowerBoundaryFixedAtZero ? 0 :
3458 fConvolutedGausDeltaPrime->GetX(maximumFraction, lowBoundSearchBoundLow, lowBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3460 // .. and the same for the upper boundary
3461 Double_t rangeEnd = 0;
3462 // If distribution starts beyond upper boundary, everything ends up in the overflow bin. So, just reduce range and Npx to minimum
3463 if (rangeStart > fkDeltaPrimeUpLimit) {
3464 rangeEnd = rangeStart + 0.00001;
3465 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3466 fConvolutedGausDeltaPrime->SetNpx(4);
3469 // Estimate upper boundary for subsequent search:
3470 Double_t upBoundSearchBoundUp = maxX + 5 * gausSigma;
3471 Double_t upBoundSearchBoundLow = maxX;
3472 while (fConvolutedGausDeltaPrime->Eval(upBoundSearchBoundUp) >= maximumFraction) {
3473 upBoundSearchBoundUp += gausSigma;
3474 upBoundSearchBoundLow += gausSigma;
3477 // For small values of the maximum: Need more precision, since finer binning!
3478 rangeEnd = fConvolutedGausDeltaPrime->GetX(maximumFraction, upBoundSearchBoundLow, upBoundSearchBoundUp, (maxX < 0.4) ? 1e-5 : 0.001);
3480 fConvolutedGausDeltaPrime->SetRange(rangeStart,rangeEnd);
3481 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3483 fConvolutedGausDeltaPrime->SetNpx(fDeltaPrimeAxis->FindFixBin(rangeEnd) - fDeltaPrimeAxis->FindFixBin(rangeStart) + 1);
3484 //fConvolutedGausDeltaPrime->SetNpx(fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeEnd)
3485 // - fhPIDdataAll->GetAxis(kDataDeltaPrimeSpecies)->FindFixBin(rangeStart) + 1);
3486 //fConvolutedGausDeltaPrime->SetNpx((rangeEnd - rangeStart) / fDeltaPrimeBinWidth + 1);
3490 printf("File: %s, Line: %d: SetParamsForConvolutedGaus -> range %f - %f, error code %d\n", (char*)__FILE__, __LINE__,
3491 rangeStart, rangeEnd, errCode);
3497 //________________________________________________________________________
3498 void AliAnalysisTaskPID::SetUpGenHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3500 // Sets bin limits for axes which are not standard binned and the axes titles.
3502 hist->SetBinEdges(kGenPt, binsPt);
3503 hist->SetBinEdges(kGenDeltaPrimeSpecies, binsDeltaPrime);
3504 hist->SetBinEdges(kGenCentrality, binsCent);
3506 if (fStoreAdditionalJetInformation)
3507 hist->SetBinEdges(kGenJetPt, binsJetPt);
3510 hist->GetAxis(kGenMCID)->SetTitle("MC PID");
3511 hist->GetAxis(kGenMCID)->SetBinLabel(1, "e");
3512 hist->GetAxis(kGenMCID)->SetBinLabel(2, "K");
3513 hist->GetAxis(kGenMCID)->SetBinLabel(3, "#mu");
3514 hist->GetAxis(kGenMCID)->SetBinLabel(4, "#pi");
3515 hist->GetAxis(kGenMCID)->SetBinLabel(5, "p");
3517 hist->GetAxis(kGenSelectSpecies)->SetTitle("Select Species");
3518 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(1, "e");
3519 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(2, "K");
3520 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(3, "#pi");
3521 hist->GetAxis(kGenSelectSpecies)->SetBinLabel(4, "p");
3523 hist->GetAxis(kGenPt)->SetTitle("p_{T} (GeV/c)");
3525 hist->GetAxis(kGenDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3527 hist->GetAxis(kGenCentrality)->SetTitle(Form("Centrality Percentile (%s)", fCentralityEstimator.Data()));
3529 if (fStoreAdditionalJetInformation) {
3530 hist->GetAxis(kGenJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3532 hist->GetAxis(kGenZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3534 hist->GetAxis(kGenXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3537 hist->GetAxis(GetIndexOfChargeAxisGen())->SetTitle("Charge (e_{0})");
3539 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetTitle("TOF PID Info");
3540 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3541 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3542 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3543 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3544 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3545 hist->GetAxis(GetIndexOfTOFpidInfoAxisGen())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3549 //________________________________________________________________________
3550 void AliAnalysisTaskPID::SetUpGenYieldHist(THnSparse* hist, Double_t* binsPt, Double_t* binsCent, Double_t* binsJetPt) const
3552 // Sets bin limits for axes which are not standard binned and the axes titles.
3554 hist->SetBinEdges(kGenYieldPt, binsPt);
3555 hist->SetBinEdges(kGenYieldCentrality, binsCent);
3556 if (fStoreAdditionalJetInformation)
3557 hist->SetBinEdges(kGenYieldJetPt, binsJetPt);
3559 for (Int_t i = 0; i < 5; i++)
3560 hist->GetAxis(kGenYieldMCID)->SetBinLabel(i + 1, AliPID::ParticleLatexName(i));
3563 hist->GetAxis(kGenYieldMCID)->SetTitle("MC PID");
3564 hist->GetAxis(kGenYieldPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3565 hist->GetAxis(kGenYieldCentrality)->SetTitle(Form("Centrality Percentile (%s)", fCentralityEstimator.Data()));
3567 if (fStoreAdditionalJetInformation) {
3568 hist->GetAxis(kGenYieldJetPt)->SetTitle("p_{T}^{jet, gen} (GeV/c)");
3570 hist->GetAxis(kGenYieldZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3572 hist->GetAxis(kGenYieldXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3575 hist->GetAxis(GetIndexOfChargeAxisGenYield())->SetTitle("Charge (e_{0})");
3579 //________________________________________________________________________
3580 void AliAnalysisTaskPID::SetUpHist(THnSparse* hist, Double_t* binsPt, Double_t* binsDeltaPrime, Double_t* binsCent, Double_t* binsJetPt) const
3582 // Sets bin limits for axes which are not standard binned and the axes titles.
3584 hist->SetBinEdges(kDataPt, binsPt);
3585 hist->SetBinEdges(kDataDeltaPrimeSpecies, binsDeltaPrime);
3586 hist->SetBinEdges(kDataCentrality, binsCent);
3588 if (fStoreAdditionalJetInformation)
3589 hist->SetBinEdges(kDataJetPt, binsJetPt);
3592 hist->GetAxis(kDataMCID)->SetTitle("MC PID");
3593 hist->GetAxis(kDataMCID)->SetBinLabel(1, "e");
3594 hist->GetAxis(kDataMCID)->SetBinLabel(2, "K");
3595 hist->GetAxis(kDataMCID)->SetBinLabel(3, "#mu");
3596 hist->GetAxis(kDataMCID)->SetBinLabel(4, "#pi");
3597 hist->GetAxis(kDataMCID)->SetBinLabel(5, "p");
3599 hist->GetAxis(kDataSelectSpecies)->SetTitle("Select Species");
3600 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(1, "e");
3601 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(2, "K");
3602 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(3, "#pi");
3603 hist->GetAxis(kDataSelectSpecies)->SetBinLabel(4, "p");
3605 hist->GetAxis(kDataPt)->SetTitle("p_{T} (GeV/c)");
3607 hist->GetAxis(kDataDeltaPrimeSpecies)->SetTitle("TPC #Delta'_{species} (arb. unit)");
3609 hist->GetAxis(kDataCentrality)->SetTitle(Form("Centrality Percentile (%s)", fCentralityEstimator.Data()));
3611 if (fStoreAdditionalJetInformation) {
3612 hist->GetAxis(kDataJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3614 hist->GetAxis(kDataZ)->SetTitle("z = p_{T}^{track} / p_{T}^{jet}");
3616 hist->GetAxis(kDataXi)->SetTitle("#xi = ln(p_{T}^{jet} / p_{T}^{track})");
3619 hist->GetAxis(GetIndexOfChargeAxisData())->SetTitle("Charge (e_{0})");
3621 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetTitle("TOF PID Info");
3622 // Offset is (TMath::Abs(kNoTOFinfo) + 1), such that bin 1 (= first label) corresponds to kNoTOFinfo (< 0)
3623 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFinfo + (TMath::Abs(kNoTOFinfo) + 1), "No TOF Info");
3624 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kNoTOFpid + (TMath::Abs(kNoTOFinfo) + 1), "No TOF PID");
3625 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFpion + (TMath::Abs(kNoTOFinfo) + 1), "#pi");
3626 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFkaon + (TMath::Abs(kNoTOFinfo) + 1), "K");
3627 hist->GetAxis(GetIndexOfTOFpidInfoAxisData())->SetBinLabel(kTOFproton + (TMath::Abs(kNoTOFinfo) + 1), "p");
3631 //________________________________________________________________________
3632 void AliAnalysisTaskPID::SetUpPtResHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt, Double_t* binsCent) const
3634 // Sets bin limits for axes which are not standard binned and the axes titles.
3636 hist->SetBinEdges(kPtResJetPt, binsJetPt);
3637 hist->SetBinEdges(kPtResGenPt, binsPt);
3638 hist->SetBinEdges(kPtResRecPt, binsPt);
3639 hist->SetBinEdges(kPtResCentrality, binsCent);
3642 hist->GetAxis(kPtResJetPt)->SetTitle("p_{T}^{jet, rec} (GeV/c)");
3643 hist->GetAxis(kPtResGenPt)->SetTitle("p_{T}^{gen} (GeV/c)");
3644 hist->GetAxis(kPtResRecPt)->SetTitle("p_{T}^{rec} (GeV/c)");
3646 hist->GetAxis(kPtResCharge)->SetTitle("Charge (e_{0})");
3647 hist->GetAxis(kPtResCentrality)->SetTitle(Form("Centrality Percentile (%s)", fCentralityEstimator.Data()));
3651 //________________________________________________________________________
3652 void AliAnalysisTaskPID::SetUpSharedClsHist(THnSparse* hist, Double_t* binsPt, Double_t* binsJetPt) const
3654 // Sets bin limits for axes which are not standard binned and the axes titles.
3656 hist->SetBinEdges(kQASharedClsJetPt, binsJetPt);
3657 hist->SetBinEdges(kQASharedClsPt, binsPt);
3660 hist->GetAxis(kQASharedClsJetPt)->SetTitle("#it{p}_{T}^{jet} (GeV/#it{c})");
3661 hist->GetAxis(kQASharedClsPt)->SetTitle("#it{p}_{T} (GeV/#it{c})");
3662 hist->GetAxis(kQASharedClsNumSharedCls)->SetTitle("#it{N}_{shared}^{cls}");
3663 hist->GetAxis(kQASharedClsPadRow)->SetTitle("Pad row");
3668 //________________________________________________________________________
3669 void AliAnalysisTaskPID::SetUpDeDxCheckHist(THnSparse* hist, const Double_t* binsPt, const Double_t* binsJetPt, const Double_t* binsEtaAbs) const
3671 // Sets bin limits for axes which are not standard binned and the axes titles.
3672 hist->SetBinEdges(kDeDxCheckP, binsPt);
3673 hist->SetBinEdges(kDeDxCheckJetPt, binsJetPt);
3674 hist->SetBinEdges(kDeDxCheckEtaAbs, binsEtaAbs);
3678 hist->GetAxis(kDeDxCheckPID)->SetTitle("PID");
3679 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(1, "e");
3680 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(2, "K");
3681 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(3, "#pi");
3682 hist->GetAxis(kDeDxCheckPID)->SetBinLabel(4, "p");
3685 hist->GetAxis(kDeDxCheckJetPt)->SetTitle("p_{T}^{jet} (GeV/c)");
3686 hist->GetAxis(kDeDxCheckEtaAbs)->SetTitle("|#eta|");
3687 hist->GetAxis(kDeDxCheckP)->SetTitle("p_{TPC} (GeV/c)");
3688 hist->GetAxis(kDeDxCheckDeDx)->SetTitle("TPC dE/dx (arb. unit)");