Fixes for pA indenfication of events
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / AliForwardUtil.cxx
CommitLineData
7984e5f7 1//
2// Utilities used in the forward multiplcity analysis
3//
4//
7e4038b5 5#include "AliForwardUtil.h"
9d99b0dd 6#include <AliAnalysisManager.h>
7#include "AliAODForwardMult.h"
8#include <AliLog.h>
9#include <AliInputEventHandler.h>
290052e7 10#include <AliAODInputHandler.h>
11#include <AliAODHandler.h>
12#include <AliAODEvent.h>
9d99b0dd 13#include <AliESDEvent.h>
290052e7 14#include <AliAnalysisTaskSE.h>
9d99b0dd 15#include <AliPhysicsSelection.h>
16#include <AliTriggerAnalysis.h>
17#include <AliMultiplicity.h>
241cca4d 18#include <TParameter.h>
7e4038b5 19#include <TH2D.h>
9d99b0dd 20#include <TH1I.h>
7f759bb7 21#include <TF1.h>
22#include <TFitResult.h>
7e4038b5 23#include <TMath.h>
7f759bb7 24#include <TError.h>
f53fb4f6 25#include <TROOT.h>
7f759bb7 26
0bd4b00f 27//====================================================================
28UShort_t
29AliForwardUtil::ParseCollisionSystem(const char* sys)
30{
7984e5f7 31 //
32 // Parse a collision system spec given in a string. Known values are
33 //
0151a6c6 34 // - "ppb", "p-pb", "pa", "p-a" which returns kPPb
35 // - "pp", "p-p" which returns kPP
36 // - "PbPb", "Pb-Pb", "A-A", which returns kPbPb
7984e5f7 37 // - Everything else gives kUnknown
38 //
39 // Parameters:
40 // sys Collision system spec
41 //
42 // Return:
43 // Collision system id
44 //
0bd4b00f 45 TString s(sys);
46 s.ToLower();
0151a6c6 47 // we do pA first to avoid pp catch on ppb string (AH)
48 if (s.Contains("p-pb") || s.Contains("ppb")) return AliForwardUtil::kPPb;
49 if (s.Contains("p-a") || s.Contains("pa")) return AliForwardUtil::kPPb;
d4d486f8 50 if (s.Contains("a-p") || s.Contains("ap")) return AliForwardUtil::kPPb;
0151a6c6 51 if (s.Contains("p-p") || s.Contains("pp")) return AliForwardUtil::kPP;
52 if (s.Contains("pb-pb") || s.Contains("pbpb")) return AliForwardUtil::kPbPb;
53 if (s.Contains("a-a") || s.Contains("aa")) return AliForwardUtil::kPbPb;
0bd4b00f 54 return AliForwardUtil::kUnknown;
55}
56//____________________________________________________________________
57const char*
58AliForwardUtil::CollisionSystemString(UShort_t sys)
59{
7984e5f7 60 //
61 // Get a string representation of the collision system
62 //
63 // Parameters:
64 // sys Collision system
65 // - kPP -> "pp"
66 // - kPbPb -> "PbPb"
67 // - anything else gives "unknown"
68 //
69 // Return:
70 // String representation of the collision system
71 //
0bd4b00f 72 switch (sys) {
73 case AliForwardUtil::kPP: return "pp";
74 case AliForwardUtil::kPbPb: return "PbPb";
0151a6c6 75 case AliForwardUtil::kPPb: return "pPb";
0bd4b00f 76 }
77 return "unknown";
78}
79//____________________________________________________________________
80UShort_t
cc83fca2 81AliForwardUtil::ParseCenterOfMassEnergy(UShort_t /* sys */, Float_t v)
0bd4b00f 82{
7984e5f7 83 //
84 // Parse the center of mass energy given as a float and return known
85 // values as a unsigned integer
86 //
87 // Parameters:
88 // sys Collision system (needed for AA)
89 // cms Center of mass energy * total charge
90 //
91 // Return:
92 // Center of mass energy per nucleon
93 //
0bd4b00f 94 Float_t energy = v;
cc83fca2 95 // Below no longer needed apparently
96 // if (sys == AliForwardUtil::kPbPb) energy = energy / 208 * 82;
0bd4b00f 97 if (TMath::Abs(energy - 900.) < 10) return 900;
98 if (TMath::Abs(energy - 2400.) < 10) return 2400;
e58000b7 99 if (TMath::Abs(energy - 2750.) < 20) return 2750;
0151a6c6 100 if (TMath::Abs(energy - 4400.) < 10) return 4400;
d4d486f8 101 if (TMath::Abs(energy - 5022.) < 10) return 5000;
0bd4b00f 102 if (TMath::Abs(energy - 5500.) < 40) return 5500;
103 if (TMath::Abs(energy - 7000.) < 10) return 7000;
4bcdcbc1 104 if (TMath::Abs(energy - 8000.) < 10) return 8000;
0bd4b00f 105 if (TMath::Abs(energy - 10000.) < 10) return 10000;
106 if (TMath::Abs(energy - 14000.) < 10) return 14000;
107 return 0;
108}
109//____________________________________________________________________
110const char*
111AliForwardUtil::CenterOfMassEnergyString(UShort_t cms)
112{
7984e5f7 113 //
114 // Get a string representation of the center of mass energy per nuclean
115 //
116 // Parameters:
117 // cms Center of mass energy per nucleon
118 //
119 // Return:
120 // String representation of the center of mass energy per nuclean
121 //
0bd4b00f 122 return Form("%04dGeV", cms);
123}
124//____________________________________________________________________
125Short_t
126AliForwardUtil::ParseMagneticField(Float_t v)
127{
7984e5f7 128 //
129 // Parse the magnetic field (in kG) as given by a floating point number
130 //
131 // Parameters:
132 // field Magnetic field in kG
133 //
134 // Return:
135 // Short integer value of magnetic field in kG
136 //
0bd4b00f 137 if (TMath::Abs(v - 5.) < 1 ) return +5;
138 if (TMath::Abs(v + 5.) < 1 ) return -5;
139 if (TMath::Abs(v) < 1) return 0;
140 return 999;
141}
142//____________________________________________________________________
143const char*
144AliForwardUtil::MagneticFieldString(Short_t f)
145{
7984e5f7 146 //
147 // Get a string representation of the magnetic field
148 //
149 // Parameters:
150 // field Magnetic field in kG
151 //
152 // Return:
153 // String representation of the magnetic field
154 //
0bd4b00f 155 return Form("%01dkG", f);
156}
290052e7 157//_____________________________________________________________________
158AliAODEvent* AliForwardUtil::GetAODEvent(AliAnalysisTaskSE* task)
159{
160 // Check if AOD is the output event
576472c1 161 if (!task) ::Fatal("GetAODEvent", "Null task given, cannot do that");
162
290052e7 163 AliAODEvent* ret = task->AODEvent();
164 if (ret) return ret;
165
166 // Check if AOD is the input event
167 ret = dynamic_cast<AliAODEvent*>(task->InputEvent());
168 if (!ret) ::Warning("GetAODEvent", "No AOD event found");
169
170 return ret;
171}
172//_____________________________________________________________________
173UShort_t AliForwardUtil::CheckForAOD()
174{
175 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
176 if (dynamic_cast<AliAODInputHandler*>(am->GetInputEventHandler())) {
177 ::Info("CheckForAOD", "Found AOD Input handler");
178 return 1;
179 }
180 if (dynamic_cast<AliAODHandler*>(am->GetOutputEventHandler())) {
181 ::Info("CheckForAOD", "Found AOD Output handler");
182 return 2;
183 }
184
185 ::Warning("CheckForAOD",
186 "Neither and input nor output AOD handler is specified");
187 return 0;
188}
189//_____________________________________________________________________
190Bool_t AliForwardUtil::CheckForTask(const char* clsOrName, Bool_t cls)
191{
192 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
193 if (!cls) {
194 AliAnalysisTask* t = am->GetTask(clsOrName);
195 if (!t) {
196 ::Warning("CheckForTask", "Task %s not found in manager", clsOrName);
197 return false;
198 }
199 ::Info("CheckForTask", "Found task %s", clsOrName);
200 return true;
201 }
202 TClass* dep = gROOT->GetClass(clsOrName);
203 if (!dep) {
204 ::Warning("CheckForTask", "Unknown class %s for needed task", clsOrName);
205 return false;
206 }
207 TIter next(am->GetTasks());
208 TObject* o = 0;
209 while ((o = next())) {
210 if (o->IsA()->InheritsFrom(dep)) {
211 ::Info("CheckForTask", "Found task of class %s: %s",
212 clsOrName, o->GetName());
213 return true;
214 }
215 }
216 ::Warning("CheckForTask", "No task of class %s was found", clsOrName);
217 return false;
218}
219
241cca4d 220//_____________________________________________________________________
221TObject* AliForwardUtil::MakeParameter(const Char_t* name, UShort_t value)
222{
223 TParameter<int>* ret = new TParameter<int>(name, value);
224 ret->SetUniqueID(value);
225 return ret;
226}
227//_____________________________________________________________________
228TObject* AliForwardUtil::MakeParameter(const Char_t* name, Int_t value)
229{
230 TParameter<int>* ret = new TParameter<int>(name, value);
231 ret->SetUniqueID(value);
232 return ret;
233}
234//_____________________________________________________________________
235TObject* AliForwardUtil::MakeParameter(const Char_t* name, Double_t value)
236{
237 TParameter<double>* ret = new TParameter<double>(name, value);
238 Float_t v = value;
239 ret->SetUniqueID(*reinterpret_cast<UInt_t*>(&v));
240 return ret;
241}
242//_____________________________________________________________________
243TObject* AliForwardUtil::MakeParameter(const Char_t* name, Bool_t value)
244{
245 TParameter<bool>* ret = new TParameter<bool>(name, value);
246 ret->SetUniqueID(value);
247 return ret;
248}
249
250//_____________________________________________________________________
251void AliForwardUtil::GetParameter(TObject* o, UShort_t& value)
252{
253 if (!o) return;
254 value = o->GetUniqueID();
255}
256//_____________________________________________________________________
257void AliForwardUtil::GetParameter(TObject* o, Int_t& value)
258{
259 if (!o) return;
260 value = o->GetUniqueID();
261}
262//_____________________________________________________________________
263void AliForwardUtil::GetParameter(TObject* o, Double_t& value)
264{
265 if (!o) return;
266 UInt_t i = o->GetUniqueID();
267 Float_t v = *reinterpret_cast<Float_t*>(&i);
268 value = v;
269}
270//_____________________________________________________________________
271void AliForwardUtil::GetParameter(TObject* o, Bool_t& value)
272{
273 if (!o) return;
274 value = o->GetUniqueID();
275}
290052e7 276
6f4a5c0d 277//_____________________________________________________________________
278Double_t AliForwardUtil::GetEtaFromStrip(UShort_t det, Char_t ring, UShort_t sec, UShort_t strip, Double_t zvtx)
279{
280 //Calculate eta from strip with vertex (redundant with AliESDFMD::Eta but support displaced vertices)
281
282 //Get max R of ring
283 Double_t maxR = 0;
284 Double_t minR = 0;
285 Bool_t inner = false;
286 switch (ring) {
287 case 'i': case 'I': maxR = 17.2; minR = 4.5213; inner = true; break;
288 case 'o': case 'O': maxR = 28.0; minR = 15.4; inner = false; break;
289 default:
290 return -99999;
291 }
292
293 Double_t rad = maxR- minR;
294 Double_t nStrips = (ring == 'I' ? 512 : 256);
295 Double_t segment = rad / nStrips;
296 Double_t r = minR + segment*strip;
297 Int_t hybrid = sec / 2;
298
299 Double_t z = 0;
300 switch (det) {
301 case 1: z = 320.266; break;
302 case 2: z = (inner ? 83.666 : 74.966); break;
303 case 3: z = (inner ? -63.066 : -74.966); break;
304 default: return -999999;
305 }
306 if ((hybrid % 2) == 0) z -= .5;
307
308 Double_t theta = TMath::ATan2(r,z-zvtx);
309 Double_t eta = -1*TMath::Log(TMath::Tan(0.5*theta));
310
311 return eta;
312}
0bd4b00f 313
314
7f759bb7 315//====================================================================
316Int_t AliForwardUtil::fgConvolutionSteps = 100;
317Double_t AliForwardUtil::fgConvolutionNSigma = 5;
318namespace {
7984e5f7 319 //
320 // The shift of the most probable value for the ROOT function TMath::Landau
321 //
7f759bb7 322 const Double_t mpshift = -0.22278298;
7984e5f7 323 //
324 // Integration normalisation
325 //
7f759bb7 326 const Double_t invSq2pi = 1. / TMath::Sqrt(2*TMath::Pi());
327
7984e5f7 328 //
329 // Utility function to use in TF1 defintition
330 //
7f759bb7 331 Double_t landauGaus1(Double_t* xp, Double_t* pp)
332 {
333 Double_t x = xp[0];
c389303e 334 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
335 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
336 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
337 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
1174780f 338 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
7f759bb7 339
1174780f 340 return constant * AliForwardUtil::LandauGaus(x, delta, xi, sigma, sigmaN);
7f759bb7 341 }
342
7984e5f7 343 //
344 // Utility function to use in TF1 defintition
345 //
7f759bb7 346 Double_t landauGausN(Double_t* xp, Double_t* pp)
347 {
348 Double_t x = xp[0];
c389303e 349 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
350 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
351 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
352 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
1174780f 353 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
c389303e 354 Int_t n = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
355 Double_t* a = &(pp[AliForwardUtil::ELossFitter::kA]);
7f759bb7 356
1174780f 357 return constant * AliForwardUtil::NLandauGaus(x, delta, xi, sigma, sigmaN,
7f759bb7 358 n, a);
359 }
7984e5f7 360 //
361 // Utility function to use in TF1 defintition
362 //
0bd4b00f 363 Double_t landauGausI(Double_t* xp, Double_t* pp)
364 {
365 Double_t x = xp[0];
366 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
367 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
368 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
369 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
1174780f 370 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
0bd4b00f 371 Int_t i = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
372
1174780f 373 return constant * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
0bd4b00f 374 }
7f759bb7 375
376
377}
378//____________________________________________________________________
379Double_t
380AliForwardUtil::Landau(Double_t x, Double_t delta, Double_t xi)
381{
7984e5f7 382 //
383 // Calculate the shifted Landau
384 // @f[
385 // f'_{L}(x;\Delta,\xi) = f_L(x;\Delta+0.22278298\xi)
386 // @f]
387 //
388 // where @f$ f_{L}@f$ is the ROOT implementation of the Landau
389 // distribution (known to have @f$ \Delta_{p}=-0.22278298@f$ for
390 // @f$\Delta=0,\xi=1@f$.
391 //
392 // Parameters:
393 // x Where to evaluate @f$ f'_{L}@f$
394 // delta Most probable value
395 // xi The 'width' of the distribution
396 //
397 // Return:
398 // @f$ f'_{L}(x;\Delta,\xi) @f$
399 //
7f759bb7 400 return TMath::Landau(x, delta - xi * mpshift, xi);
401}
402//____________________________________________________________________
403Double_t
404AliForwardUtil::LandauGaus(Double_t x, Double_t delta, Double_t xi,
1174780f 405 Double_t sigma, Double_t sigmaN)
7f759bb7 406{
7984e5f7 407 //
408 // Calculate the value of a Landau convolved with a Gaussian
409 //
410 // @f[
411 // f(x;\Delta,\xi,\sigma') = \frac{1}{\sigma' \sqrt{2 \pi}}
412 // \int_{-\infty}^{+\infty} d\Delta' f'_{L}(x;\Delta',\xi)
413 // \exp{-\frac{(\Delta-\Delta')^2}{2\sigma'^2}}
414 // @f]
415 //
416 // where @f$ f'_{L}@f$ is the Landau distribution, @f$ \Delta@f$ the
417 // energy loss, @f$ \xi@f$ the width of the Landau, and
418 // @f$ \sigma'^2=\sigma^2-\sigma_n^2 @f$. Here, @f$\sigma@f$ is the
419 // variance of the Gaussian, and @f$\sigma_n@f$ is a parameter modelling
420 // noise in the detector.
421 //
422 // Note that this function uses the constants fgConvolutionSteps and
423 // fgConvolutionNSigma
424 //
425 // References:
426 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
427 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
428 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
429 //
430 // Parameters:
431 // x where to evaluate @f$ f@f$
432 // delta @f$ \Delta@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
433 // xi @f$ \xi@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
434 // sigma @f$ \sigma@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
435 // sigma_n @f$ \sigma_n@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
436 //
437 // Return:
438 // @f$ f@f$ evaluated at @f$ x@f$.
439 //
7f759bb7 440 Double_t deltap = delta - xi * mpshift;
1174780f 441 Double_t sigma2 = sigmaN*sigmaN + sigma*sigma;
442 Double_t sigma1 = sigmaN == 0 ? sigma : TMath::Sqrt(sigma2);
7f759bb7 443 Double_t xlow = x - fgConvolutionNSigma * sigma1;
c389303e 444 Double_t xhigh = x + fgConvolutionNSigma * sigma1;
7f759bb7 445 Double_t step = (xhigh - xlow) / fgConvolutionSteps;
446 Double_t sum = 0;
447
448 for (Int_t i = 0; i <= fgConvolutionSteps/2; i++) {
c389303e 449 Double_t x1 = xlow + (i - .5) * step;
450 Double_t x2 = xhigh - (i - .5) * step;
7f759bb7 451
452 sum += TMath::Landau(x1, deltap, xi, kTRUE) * TMath::Gaus(x, x1, sigma1);
453 sum += TMath::Landau(x2, deltap, xi, kTRUE) * TMath::Gaus(x, x2, sigma1);
454 }
455 return step * sum * invSq2pi / sigma1;
456}
457
0bd4b00f 458//____________________________________________________________________
459Double_t
460AliForwardUtil::ILandauGaus(Double_t x, Double_t delta, Double_t xi,
1174780f 461 Double_t sigma, Double_t sigmaN, Int_t i)
0bd4b00f 462{
7984e5f7 463 //
464 // Evaluate
465 // @f[
466 // f_i(x;\Delta,\xi,\sigma') = f(x;\Delta_i,\xi_i,\sigma_i')
467 // @f]
468 // corresponding to @f$ i@f$ particles i.e., with the substitutions
469 // @f{eqnarray*}{
470 // \Delta \rightarrow \Delta_i &=& i(\Delta + \xi\log(i))
471 // \xi \rightarrow \xi_i &=& i \xi
472 // \sigma \rightarrow \sigma_i &=& \sqrt{i}\sigma
473 // \sigma'^2 \rightarrow \sigma_i'^2 &=& \sigma_n^2 + \sigma_i^2
474 // @f}
475 //
476 // Parameters:
477 // x Where to evaluate
478 // delta @f$ \Delta@f$
479 // xi @f$ \xi@f$
480 // sigma @f$ \sigma@f$
481 // sigma_n @f$ \sigma_n@f$
482 // i @f$ i @f$
483 //
484 // Return:
485 // @f$ f_i @f$ evaluated
486 //
1174780f 487 Double_t deltaI = (i == 1 ? delta : i * (delta + xi * TMath::Log(i)));
488 Double_t xiI = i * xi;
489 Double_t sigmaI = (i == 1 ? sigma : TMath::Sqrt(Double_t(i))*sigma);
490 if (sigmaI < 1e-10) {
0bd4b00f 491 // Fall back to landau
1174780f 492 return AliForwardUtil::Landau(x, deltaI, xiI);
0bd4b00f 493 }
1174780f 494 return AliForwardUtil::LandauGaus(x, deltaI, xiI, sigmaI, sigmaN);
0bd4b00f 495}
496
497//____________________________________________________________________
498Double_t
499AliForwardUtil::IdLandauGausdPar(Double_t x,
500 UShort_t par, Double_t dPar,
501 Double_t delta, Double_t xi,
1174780f 502 Double_t sigma, Double_t sigmaN,
0bd4b00f 503 Int_t i)
504{
7984e5f7 505 //
506 // Numerically evaluate
507 // @f[
508 // \left.\frac{\partial f_i}{\partial p_i}\right|_{x}
509 // @f]
510 // where @f$ p_i@f$ is the @f$ i^{\mbox{th}}@f$ parameter. The mapping
511 // of the parameters is given by
512 //
513 // - 0: @f$\Delta@f$
514 // - 1: @f$\xi@f$
515 // - 2: @f$\sigma@f$
516 // - 3: @f$\sigma_n@f$
517 //
518 // This is the partial derivative with respect to the parameter of
519 // the response function corresponding to @f$ i@f$ particles i.e.,
520 // with the substitutions
521 // @f[
522 // \Delta \rightarrow \Delta_i = i(\Delta + \xi\log(i))
523 // \xi \rightarrow \xi_i = i \xi
524 // \sigma \rightarrow \sigma_i = \sqrt{i}\sigma
525 // \sigma'^2 \rightarrow \sigma_i'^2 = \sigma_n^2 + \sigma_i^2
526 // @f]
527 //
528 // Parameters:
529 // x Where to evaluate
530 // ipar Parameter number
531 // dp @f$ \epsilon\delta p_i@f$ for some value of @f$\epsilon@f$
532 // delta @f$ \Delta@f$
533 // xi @f$ \xi@f$
534 // sigma @f$ \sigma@f$
535 // sigma_n @f$ \sigma_n@f$
536 // i @f$ i@f$
537 //
538 // Return:
539 // @f$ f_i@f$ evaluated
540 //
0bd4b00f 541 if (dPar == 0) return 0;
542 Double_t dp = dPar;
543 Double_t d2 = dPar / 2;
1174780f 544 Double_t deltaI = i * (delta + xi * TMath::Log(i));
545 Double_t xiI = i * xi;
0bd4b00f 546 Double_t si = TMath::Sqrt(Double_t(i));
1174780f 547 Double_t sigmaI = si*sigma;
0bd4b00f 548 Double_t y1 = 0;
549 Double_t y2 = 0;
550 Double_t y3 = 0;
551 Double_t y4 = 0;
552 switch (par) {
553 case 0:
1174780f 554 y1 = ILandauGaus(x, deltaI+i*dp, xiI, sigmaI, sigmaN, i);
555 y2 = ILandauGaus(x, deltaI+i*d2, xiI, sigmaI, sigmaN, i);
556 y3 = ILandauGaus(x, deltaI-i*d2, xiI, sigmaI, sigmaN, i);
557 y4 = ILandauGaus(x, deltaI-i*dp, xiI, sigmaI, sigmaN, i);
0bd4b00f 558 break;
559 case 1:
1174780f 560 y1 = ILandauGaus(x, deltaI, xiI+i*dp, sigmaI, sigmaN, i);
561 y2 = ILandauGaus(x, deltaI, xiI+i*d2, sigmaI, sigmaN, i);
562 y3 = ILandauGaus(x, deltaI, xiI-i*d2, sigmaI, sigmaN, i);
563 y4 = ILandauGaus(x, deltaI, xiI-i*dp, sigmaI, sigmaN, i);
0bd4b00f 564 break;
565 case 2:
1174780f 566 y1 = ILandauGaus(x, deltaI, xiI, sigmaI+si*dp, sigmaN, i);
567 y2 = ILandauGaus(x, deltaI, xiI, sigmaI+si*d2, sigmaN, i);
568 y3 = ILandauGaus(x, deltaI, xiI, sigmaI-si*d2, sigmaN, i);
569 y4 = ILandauGaus(x, deltaI, xiI, sigmaI-si*dp, sigmaN, i);
0bd4b00f 570 break;
571 case 3:
1174780f 572 y1 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+dp, i);
573 y2 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+d2, i);
574 y3 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-d2, i);
575 y4 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-dp, i);
0bd4b00f 576 break;
577 default:
578 return 0;
579 }
580
581 Double_t d0 = y1 - y4;
582 Double_t d1 = 2 * (y2 - y3);
583
584 Double_t g = 1/(2*dp) * (4*d1 - d0) / 3;
585
586 return g;
587}
588
7f759bb7 589//____________________________________________________________________
590Double_t
591AliForwardUtil::NLandauGaus(Double_t x, Double_t delta, Double_t xi,
1174780f 592 Double_t sigma, Double_t sigmaN, Int_t n,
fb3430ac 593 const Double_t* a)
7f759bb7 594{
7984e5f7 595 //
596 // Evaluate
597 // @f[
598 // f_N(x;\Delta,\xi,\sigma') = \sum_{i=1}^N a_i f_i(x;\Delta,\xi,\sigma'a)
599 // @f]
600 //
601 // where @f$ f(x;\Delta,\xi,\sigma')@f$ is the convolution of a
602 // Landau with a Gaussian (see LandauGaus). Note that
603 // @f$ a_1 = 1@f$, @f$\Delta_i = i(\Delta_1 + \xi\log(i))@f$,
604 // @f$\xi_i=i\xi_1@f$, and @f$\sigma_i'^2 = \sigma_n^2 + i\sigma_1^2@f$.
605 //
606 // References:
607 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
608 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
609 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
610 //
611 // Parameters:
612 // x Where to evaluate @f$ f_N@f$
613 // delta @f$ \Delta_1@f$
614 // xi @f$ \xi_1@f$
615 // sigma @f$ \sigma_1@f$
616 // sigma_n @f$ \sigma_n@f$
617 // n @f$ N@f$ in the sum above.
618 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
619 // @f$ i > 1@f$
620 //
621 // Return:
622 // @f$ f_N(x;\Delta,\xi,\sigma')@f$
623 //
1174780f 624 Double_t result = ILandauGaus(x, delta, xi, sigma, sigmaN, 1);
0bd4b00f 625 for (Int_t i = 2; i <= n; i++)
1174780f 626 result += a[i-2] * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
7f759bb7 627 return result;
628}
0bd4b00f 629namespace {
630 const Int_t kColors[] = { kRed+1,
631 kPink+3,
632 kMagenta+2,
633 kViolet+2,
634 kBlue+1,
635 kAzure+3,
636 kCyan+1,
637 kTeal+2,
638 kGreen+2,
639 kSpring+3,
640 kYellow+2,
641 kOrange+2 };
642}
643
644//____________________________________________________________________
645TF1*
646AliForwardUtil::MakeNLandauGaus(Double_t c,
647 Double_t delta, Double_t xi,
1174780f 648 Double_t sigma, Double_t sigmaN, Int_t n,
fb3430ac 649 const Double_t* a,
0bd4b00f 650 Double_t xmin, Double_t xmax)
651{
7984e5f7 652 //
653 // Generate a TF1 object of @f$ f_N@f$
654 //
655 // Parameters:
656 // c Constant
657 // delta @f$ \Delta@f$
658 // xi @f$ \xi_1@f$
659 // sigma @f$ \sigma_1@f$
660 // sigma_n @f$ \sigma_n@f$
661 // n @f$ N@f$ - how many particles to sum to
662 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
663 // @f$ i > 1@f$
664 // xmin Least value of range
665 // xmax Largest value of range
666 //
667 // Return:
668 // Newly allocated TF1 object
669 //
0bd4b00f 670 Int_t npar = AliForwardUtil::ELossFitter::kN+n;
671 TF1* landaun = new TF1(Form("nlandau%d", n), &landauGausN,xmin,xmax,npar);
672 // landaun->SetLineStyle(((n-2) % 10)+2); // start at dashed
673 landaun->SetLineColor(kColors[((n-1) % 12)]); // start at red
674 landaun->SetLineWidth(2);
675 landaun->SetNpx(500);
676 landaun->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "N");
677
678 // Set the initial parameters from the seed fit
679 landaun->SetParameter(AliForwardUtil::ELossFitter::kC, c);
680 landaun->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
681 landaun->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
682 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
1174780f 683 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
0bd4b00f 684 landaun->FixParameter(AliForwardUtil::ELossFitter::kN, n);
685
686 // Set the range and name of the scale parameters
687 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
688 landaun->SetParameter(AliForwardUtil::ELossFitter::kA+i-2, a[i-2]);
689 landaun->SetParName(AliForwardUtil::ELossFitter::kA+i-2, Form("a_{%d}", i));
690 }
691 return landaun;
692}
693//____________________________________________________________________
694TF1*
695AliForwardUtil::MakeILandauGaus(Double_t c,
696 Double_t delta, Double_t xi,
1174780f 697 Double_t sigma, Double_t sigmaN, Int_t i,
0bd4b00f 698 Double_t xmin, Double_t xmax)
699{
7984e5f7 700 //
701 // Generate a TF1 object of @f$ f_I@f$
702 //
703 // Parameters:
704 // c Constant
705 // delta @f$ \Delta@f$
706 // xi @f$ \xi_1@f$
707 // sigma @f$ \sigma_1@f$
708 // sigma_n @f$ \sigma_n@f$
709 // i @f$ i@f$ - the number of particles
710 // xmin Least value of range
711 // xmax Largest value of range
712 //
713 // Return:
714 // Newly allocated TF1 object
715 //
0bd4b00f 716 Int_t npar = AliForwardUtil::ELossFitter::kN+1;
717 TF1* landaui = new TF1(Form("ilandau%d", i), &landauGausI,xmin,xmax,npar);
718 // landaui->SetLineStyle(((i-2) % 10)+2); // start at dashed
719 landaui->SetLineColor(kColors[((i-1) % 12)]); // start at red
720 landaui->SetLineWidth(1);
721 landaui->SetNpx(500);
722 landaui->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "i");
723
724 // Set the initial parameters from the seed fit
725 landaui->SetParameter(AliForwardUtil::ELossFitter::kC, c);
726 landaui->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
727 landaui->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
728 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
1174780f 729 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
0bd4b00f 730 landaui->FixParameter(AliForwardUtil::ELossFitter::kN, i);
731
732 return landaui;
733}
7f759bb7 734
735//====================================================================
736AliForwardUtil::ELossFitter::ELossFitter(Double_t lowCut,
737 Double_t maxRange,
738 UShort_t minusBins)
739 : fLowCut(lowCut), fMaxRange(maxRange), fMinusBins(minusBins),
740 fFitResults(0), fFunctions(0)
741{
7984e5f7 742 //
743 // Constructor
744 //
745 // Parameters:
746 // lowCut Lower cut of spectrum - data below this cuts is ignored
747 // maxRange Maximum range to fit to
748 // minusBins The number of bins below maximum to use
749 //
7f759bb7 750 fFitResults.SetOwner();
751 fFunctions.SetOwner();
752}
753//____________________________________________________________________
754AliForwardUtil::ELossFitter::~ELossFitter()
755{
7984e5f7 756 //
757 // Destructor
758 //
759 //
7f759bb7 760 fFitResults.Delete();
761 fFunctions.Delete();
762}
763//____________________________________________________________________
764void
765AliForwardUtil::ELossFitter::Clear()
766{
7984e5f7 767 //
768 // Clear internal arrays
769 //
770 //
7f759bb7 771 fFitResults.Clear();
772 fFunctions.Clear();
773}
774//____________________________________________________________________
775TF1*
776AliForwardUtil::ELossFitter::Fit1Particle(TH1* dist, Double_t sigman)
777{
7984e5f7 778 //
779 // Fit a 1-particle signal to the passed energy loss distribution
780 //
781 // Note that this function clears the internal arrays first
782 //
783 // Parameters:
784 // dist Data to fit the function to
785 // sigman If larger than zero, the initial guess of the
786 // detector induced noise. If zero or less, then this
787 // parameter is ignored in the fit (fixed at 0)
788 //
789 // Return:
790 // The function fitted to the data
791 //
792
7f759bb7 793 // Clear the cache
794 Clear();
795
796 // Find the fit range
797 dist->GetXaxis()->SetRangeUser(fLowCut, fMaxRange);
798
7f759bb7 799 // Get the bin with maximum
800 Int_t maxBin = dist->GetMaximumBin();
801 Double_t maxE = dist->GetBinLowEdge(maxBin);
802
803 // Get the low edge
804 dist->GetXaxis()->SetRangeUser(fLowCut, maxE);
805 Int_t minBin = maxBin - fMinusBins; // dist->GetMinimumBin();
806 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
807 Double_t maxEE = dist->GetBinCenter(maxBin+2*fMinusBins);
808
809 // Restore the range
810 dist->GetXaxis()->SetRangeUser(0, fMaxRange);
811
812 // Define the function to fit
0bd4b00f 813 TF1* landau1 = new TF1("landau1", landauGaus1, minE,maxEE,kSigmaN+1);
7f759bb7 814
815 // Set initial guesses, parameter names, and limits
c389303e 816 landau1->SetParameters(1,0.5,0.07,0.1,sigman);
7f759bb7 817 landau1->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
c389303e 818 landau1->SetNpx(500);
819 landau1->SetParLimits(kDelta, minE, fMaxRange);
820 landau1->SetParLimits(kXi, 0.00, fMaxRange);
821 landau1->SetParLimits(kSigma, 0.01, 0.1);
822 if (sigman <= 0) landau1->FixParameter(kSigmaN, 0);
823 else landau1->SetParLimits(kSigmaN, 0, fMaxRange);
7f759bb7 824
825 // Do the fit, getting the result object
826 TFitResultPtr r = dist->Fit(landau1, "RNQS", "", minE, maxEE);
c389303e 827 landau1->SetRange(minE, fMaxRange);
7f759bb7 828 fFitResults.AddAtAndExpand(new TFitResult(*r), 0);
829 fFunctions.AddAtAndExpand(landau1, 0);
830
831 return landau1;
832}
833//____________________________________________________________________
834TF1*
835AliForwardUtil::ELossFitter::FitNParticle(TH1* dist, UShort_t n,
836 Double_t sigman)
837{
7984e5f7 838 //
839 // Fit a N-particle signal to the passed energy loss distribution
840 //
841 // If there's no 1-particle fit present, it does that first
842 //
843 // Parameters:
844 // dist Data to fit the function to
845 // n Number of particle signals to fit
846 // sigman If larger than zero, the initial guess of the
847 // detector induced noise. If zero or less, then this
848 // parameter is ignored in the fit (fixed at 0)
849 //
850 // Return:
851 // The function fitted to the data
852 //
853
7f759bb7 854 // Get the seed fit result
855 TFitResult* r = static_cast<TFitResult*>(fFitResults.At(0));
856 TF1* f = static_cast<TF1*>(fFunctions.At(0));
857 if (!r || !f) {
858 f = Fit1Particle(dist, sigman);
859 r = static_cast<TFitResult*>(fFitResults.At(0));
860 if (!r || !f) {
861 ::Warning("FitNLandau", "No first shot at landau fit");
862 return 0;
863 }
864 }
865
866 // Get some parameters from seed fit
c389303e 867 Double_t delta1 = r->Parameter(kDelta);
868 Double_t xi1 = r->Parameter(kXi);
7f759bb7 869 Double_t maxEi = n * (delta1 + xi1 * TMath::Log(n)) + 2 * n * xi1;
870 Double_t minE = f->GetXmin();
871
0bd4b00f 872 // Array of weights
873 TArrayD a(n-1);
874 for (UShort_t i = 2; i <= n; i++)
875 a.fArray[i-2] = (n == 2 ? 0.05 : 0.000001);
7f759bb7 876 // Make the fit function
0bd4b00f 877 TF1* landaun = MakeNLandauGaus(r->Parameter(kC),
878 r->Parameter(kDelta),
879 r->Parameter(kXi),
880 r->Parameter(kSigma),
881 r->Parameter(kSigmaN),
882 n,a.fArray,minE,maxEi);
c389303e 883 landaun->SetParLimits(kDelta, minE, fMaxRange); // Delta
884 landaun->SetParLimits(kXi, 0.00, fMaxRange); // xi
885 landaun->SetParLimits(kSigma, 0.01, 1); // sigma
886 // Check if we're using the noise sigma
887 if (sigman <= 0) landaun->FixParameter(kSigmaN, 0);
888 else landaun->SetParLimits(kSigmaN, 0, fMaxRange);
7f759bb7 889
890 // Set the range and name of the scale parameters
891 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
c389303e 892 landaun->SetParLimits(kA+i-2, 0,1);
7f759bb7 893 }
894
895 // Do the fit
896 TFitResultPtr tr = dist->Fit(landaun, "RSQN", "", minE, maxEi);
897
c389303e 898 landaun->SetRange(minE, fMaxRange);
7f759bb7 899 fFitResults.AddAtAndExpand(new TFitResult(*tr), n-1);
900 fFunctions.AddAtAndExpand(landaun, n-1);
901
902 return landaun;
903}
7e4038b5 904
905//====================================================================
906AliForwardUtil::Histos::~Histos()
907{
7984e5f7 908 //
909 // Destructor
910 //
7e4038b5 911 if (fFMD1i) delete fFMD1i;
912 if (fFMD2i) delete fFMD2i;
913 if (fFMD2o) delete fFMD2o;
914 if (fFMD3i) delete fFMD3i;
915 if (fFMD3o) delete fFMD3o;
916}
917
918//____________________________________________________________________
919TH2D*
920AliForwardUtil::Histos::Make(UShort_t d, Char_t r,
921 const TAxis& etaAxis) const
922{
7984e5f7 923 //
924 // Make a histogram
925 //
926 // Parameters:
927 // d Detector
928 // r Ring
929 // etaAxis Eta axis to use
930 //
931 // Return:
932 // Newly allocated histogram
933 //
7e4038b5 934 Int_t ns = (r == 'I' || r == 'i') ? 20 : 40;
935 TH2D* hist = new TH2D(Form("FMD%d%c_cache", d, r),
936 Form("FMD%d%c cache", d, r),
937 etaAxis.GetNbins(), etaAxis.GetXmin(),
938 etaAxis.GetXmax(), ns, 0, 2*TMath::Pi());
939 hist->SetXTitle("#eta");
940 hist->SetYTitle("#phi [radians]");
941 hist->SetZTitle("d^{2}N_{ch}/d#etad#phi");
942 hist->Sumw2();
943 hist->SetDirectory(0);
944
945 return hist;
946}
947//____________________________________________________________________
948void
949AliForwardUtil::Histos::Init(const TAxis& etaAxis)
950{
7984e5f7 951 //
952 // Initialize the object
953 //
954 // Parameters:
955 // etaAxis Eta axis to use
956 //
7e4038b5 957 fFMD1i = Make(1, 'I', etaAxis);
958 fFMD2i = Make(2, 'I', etaAxis);
959 fFMD2o = Make(2, 'O', etaAxis);
960 fFMD3i = Make(3, 'I', etaAxis);
961 fFMD3o = Make(3, 'O', etaAxis);
962}
963//____________________________________________________________________
964void
965AliForwardUtil::Histos::Clear(Option_t* option)
966{
7984e5f7 967 //
968 // Clear data
969 //
970 // Parameters:
971 // option Not used
972 //
422a78c8 973 if (fFMD1i) fFMD1i->Reset(option);
974 if (fFMD2i) fFMD2i->Reset(option);
975 if (fFMD2o) fFMD2o->Reset(option);
976 if (fFMD3i) fFMD3i->Reset(option);
977 if (fFMD3o) fFMD3o->Reset(option);
7e4038b5 978}
979
980//____________________________________________________________________
981TH2D*
982AliForwardUtil::Histos::Get(UShort_t d, Char_t r) const
983{
7984e5f7 984 //
985 // Get the histogram for a particular detector,ring
986 //
987 // Parameters:
988 // d Detector
989 // r Ring
990 //
991 // Return:
992 // Histogram for detector,ring or nul
993 //
7e4038b5 994 switch (d) {
995 case 1: return fFMD1i;
996 case 2: return (r == 'I' || r == 'i' ? fFMD2i : fFMD2o);
997 case 3: return (r == 'I' || r == 'i' ? fFMD3i : fFMD3o);
998 }
999 return 0;
1000}
9d99b0dd 1001//====================================================================
1002TList*
1003AliForwardUtil::RingHistos::DefineOutputList(TList* d) const
1004{
7984e5f7 1005 //
1006 // Define the outout list in @a d
1007 //
1008 // Parameters:
1009 // d Where to put the output list
1010 //
1011 // Return:
1012 // Newly allocated TList object or null
1013 //
9d99b0dd 1014 if (!d) return 0;
1015 TList* list = new TList;
5bb5d1f6 1016 list->SetOwner();
9d99b0dd 1017 list->SetName(fName.Data());
1018 d->Add(list);
1019 return list;
1020}
1021//____________________________________________________________________
1022TList*
fb3430ac 1023AliForwardUtil::RingHistos::GetOutputList(const TList* d) const
9d99b0dd 1024{
7984e5f7 1025 //
1026 // Get our output list from the container @a d
1027 //
1028 // Parameters:
1029 // d where to get the output list from
1030 //
1031 // Return:
1032 // The found TList or null
1033 //
9d99b0dd 1034 if (!d) return 0;
1035 TList* list = static_cast<TList*>(d->FindObject(fName.Data()));
1036 return list;
1037}
1038
1039//____________________________________________________________________
1040TH1*
fb3430ac 1041AliForwardUtil::RingHistos::GetOutputHist(const TList* d, const char* name) const
9d99b0dd 1042{
7984e5f7 1043 //
1044 // Find a specific histogram in the source list @a d
1045 //
1046 // Parameters:
1047 // d (top)-container
1048 // name Name of histogram
1049 //
1050 // Return:
1051 // Found histogram or null
1052 //
9d99b0dd 1053 return static_cast<TH1*>(d->FindObject(name));
1054}
1055
f53fb4f6 1056//====================================================================
1057AliForwardUtil::DebugGuard::DebugGuard(Int_t lvl, Int_t msgLvl,
1058 const char* format, ...)
1059 : fMsg("")
1060{
1061 if (lvl < msgLvl) return;
1062 va_list ap;
1063 va_start(ap, format);
81a9a914 1064 Format(fMsg, format, ap);
f53fb4f6 1065 va_end(ap);
81a9a914 1066 Output(+1, fMsg);
f53fb4f6 1067}
1068//____________________________________________________________________
1069AliForwardUtil::DebugGuard::~DebugGuard()
1070{
1071 if (fMsg.IsNull()) return;
81a9a914 1072 Output(-1, fMsg);
1073}
1074//____________________________________________________________________
1075void
1076AliForwardUtil::DebugGuard::Message(Int_t lvl, Int_t msgLvl,
1077 const char* format, ...)
1078{
1079 if (lvl < msgLvl) return;
1080 TString msg;
1081 va_list ap;
1082 va_start(ap, format);
1083 Format(msg, format, ap);
1084 va_end(ap);
1085 Output(0, msg);
1086}
1087
1088//____________________________________________________________________
1089void
1090AliForwardUtil::DebugGuard::Format(TString& out, const char* format, va_list ap)
1091{
1092 static char buf[512];
1093 Int_t n = gROOT->GetDirLevel() + 2;
1094 for (Int_t i = 0; i < n; i++) buf[i] = ' ';
1095 vsnprintf(&(buf[n]), 511-n, format, ap);
1096 buf[511] = '\0';
1097 out = buf;
f53fb4f6 1098}
1099//____________________________________________________________________
1100void
81a9a914 1101AliForwardUtil::DebugGuard::Output(int in, TString& msg)
f53fb4f6 1102{
81a9a914 1103 msg[0] = (in > 0 ? '>' : in < 0 ? '<' : '=');
1104 AliLog::Message(AliLog::kInfo, msg, 0, 0, "PWGLF/forward", 0, 0);
1105 if (in > 0) gROOT->IncreaseDirLevel();
1106 else if (in < 0) gROOT->DecreaseDirLevel();
f53fb4f6 1107}
1108
1109
1110
7e4038b5 1111//
1112// EOF
1113//