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