2 // Utilities used in the forward multiplcity analysis
5 #include "AliForwardUtil.h"
6 #include <AliAnalysisManager.h>
7 #include "AliAODForwardMult.h"
9 #include <AliInputEventHandler.h>
10 #include <AliAODInputHandler.h>
11 #include <AliAODHandler.h>
12 #include <AliAODEvent.h>
13 #include <AliESDEvent.h>
14 #include <AliAnalysisTaskSE.h>
15 #include <AliPhysicsSelection.h>
16 #include <AliTriggerAnalysis.h>
17 #include <AliMultiplicity.h>
18 #include <TParameter.h>
22 #include <TFitResult.h>
27 //====================================================================
29 AliForwardUtil::ParseCollisionSystem(const char* sys)
32 // Parse a collision system spec given in a string. Known values are
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
37 // - Everything else gives kUnknown
40 // sys Collision system spec
43 // Collision system id
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("a-p") || s.Contains("ap")) return AliForwardUtil::kPPb;
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;
54 return AliForwardUtil::kUnknown;
56 //____________________________________________________________________
58 AliForwardUtil::CollisionSystemString(UShort_t sys)
61 // Get a string representation of the collision system
64 // sys Collision system
67 // - anything else gives "unknown"
70 // String representation of the collision system
73 case AliForwardUtil::kPP: return "pp";
74 case AliForwardUtil::kPbPb: return "PbPb";
75 case AliForwardUtil::kPPb: return "pPb";
79 //____________________________________________________________________
81 AliForwardUtil::BeamRapidity(Float_t beam, UShort_t z, UShort_t a)
83 const Double_t pMass = 9.38271999999999995e-01;
84 const Double_t nMass = 9.39564999999999984e-01;
85 Double_t beamE = z * beam / 2;
86 Double_t beamM = z * pMass + (a - z) * nMass;
87 Double_t beamP = TMath::Sqrt(beamE * beamE - beamM * beamM);
88 Double_t beamY = .5* TMath::Log((beamE+beamP) / (beamE-beamP));
91 //____________________________________________________________________
93 AliForwardUtil::CenterOfMassEnergy(Float_t beam,
99 // Calculate the center of mass energy given target/projectile
100 // mass and charge numbers
103 return TMath::Sqrt(Float_t(z1*z2)/a1/a2) * beam;
105 //____________________________________________________________________
107 AliForwardUtil::CenterOfMassRapidity(UShort_t z1,
112 // Calculate the center of mass rapidity (shift) given target/projectile
113 // mass and charge numbers
116 if (z2 == z1 && a2 == a1) return 0;
117 return .5 * TMath::Log(Float_t(z1*a2)/z2/a1);
120 //____________________________________________________________________
122 AliForwardUtil::ParseCenterOfMassEnergy(UShort_t sys, Float_t beam)
125 // Parse the center of mass energy given as a float and return known
126 // values as a unsigned integer
129 // sys Collision system (needed for AA)
130 // beam Center of mass energy * total charge
133 // Center of mass energy per nucleon
135 Float_t energy = beam;
136 // Below no longer needed apparently
137 // if (sys == AliForwardUtil::kPbPb) energy = energy / 208 * 82;
138 if (sys == AliForwardUtil::kPPb)
139 energy = CenterOfMassEnergy(beam, 82, 208, 1, 1);
140 if (TMath::Abs(energy - 900.) < 10) return 900;
141 if (TMath::Abs(energy - 2400.) < 10) return 2400;
142 if (TMath::Abs(energy - 2750.) < 20) return 2750;
143 if (TMath::Abs(energy - 4400.) < 10) return 4400;
144 if (TMath::Abs(energy - 5022.) < 10) return 5023;
145 if (TMath::Abs(energy - 5500.) < 40) return 5500;
146 if (TMath::Abs(energy - 7000.) < 10) return 7000;
147 if (TMath::Abs(energy - 8000.) < 10) return 8000;
148 if (TMath::Abs(energy - 10000.) < 10) return 10000;
149 if (TMath::Abs(energy - 14000.) < 10) return 14000;
152 //____________________________________________________________________
154 AliForwardUtil::CenterOfMassEnergyString(UShort_t cms)
157 // Get a string representation of the center of mass energy per nuclean
160 // cms Center of mass energy per nucleon
163 // String representation of the center of mass energy per nuclean
165 return Form("%04dGeV", cms);
167 //____________________________________________________________________
169 AliForwardUtil::ParseMagneticField(Float_t v)
172 // Parse the magnetic field (in kG) as given by a floating point number
175 // field Magnetic field in kG
178 // Short integer value of magnetic field in kG
180 if (TMath::Abs(v - 5.) < 1 ) return +5;
181 if (TMath::Abs(v + 5.) < 1 ) return -5;
182 if (TMath::Abs(v) < 1) return 0;
185 //____________________________________________________________________
187 AliForwardUtil::MagneticFieldString(Short_t f)
190 // Get a string representation of the magnetic field
193 // field Magnetic field in kG
196 // String representation of the magnetic field
198 return Form("%01dkG", f);
200 //_____________________________________________________________________
201 AliAODEvent* AliForwardUtil::GetAODEvent(AliAnalysisTaskSE* task)
203 // Check if AOD is the output event
204 if (!task) ::Fatal("GetAODEvent", "Null task given, cannot do that");
206 AliAODEvent* ret = task->AODEvent();
209 // Check if AOD is the input event
210 ret = dynamic_cast<AliAODEvent*>(task->InputEvent());
211 if (!ret) ::Warning("GetAODEvent", "No AOD event found");
215 //_____________________________________________________________________
216 UShort_t AliForwardUtil::CheckForAOD()
218 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
219 if (dynamic_cast<AliAODInputHandler*>(am->GetInputEventHandler())) {
220 ::Info("CheckForAOD", "Found AOD Input handler");
223 if (dynamic_cast<AliAODHandler*>(am->GetOutputEventHandler())) {
224 ::Info("CheckForAOD", "Found AOD Output handler");
228 ::Warning("CheckForAOD",
229 "Neither and input nor output AOD handler is specified");
232 //_____________________________________________________________________
233 Bool_t AliForwardUtil::CheckForTask(const char* clsOrName, Bool_t cls)
235 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
237 AliAnalysisTask* t = am->GetTask(clsOrName);
239 ::Warning("CheckForTask", "Task %s not found in manager", clsOrName);
242 ::Info("CheckForTask", "Found task %s", clsOrName);
245 TClass* dep = gROOT->GetClass(clsOrName);
247 ::Warning("CheckForTask", "Unknown class %s for needed task", clsOrName);
250 TIter next(am->GetTasks());
252 while ((o = next())) {
253 if (o->IsA()->InheritsFrom(dep)) {
254 ::Info("CheckForTask", "Found task of class %s: %s",
255 clsOrName, o->GetName());
259 ::Warning("CheckForTask", "No task of class %s was found", clsOrName);
263 //_____________________________________________________________________
264 TObject* AliForwardUtil::MakeParameter(const Char_t* name, UShort_t value)
266 TParameter<int>* ret = new TParameter<int>(name, value);
267 ret->SetUniqueID(value);
270 //_____________________________________________________________________
271 TObject* AliForwardUtil::MakeParameter(const Char_t* name, Int_t value)
273 TParameter<int>* ret = new TParameter<int>(name, value);
274 ret->SetUniqueID(value);
277 //_____________________________________________________________________
278 TObject* AliForwardUtil::MakeParameter(const Char_t* name, Double_t value)
280 TParameter<double>* ret = new TParameter<double>(name, value);
282 UInt_t* tmp = reinterpret_cast<UInt_t*>(&v);
283 ret->SetUniqueID(*tmp);
286 //_____________________________________________________________________
287 TObject* AliForwardUtil::MakeParameter(const Char_t* name, Bool_t value)
289 TParameter<bool>* ret = new TParameter<bool>(name, value);
290 ret->SetUniqueID(value);
294 //_____________________________________________________________________
295 void AliForwardUtil::GetParameter(TObject* o, UShort_t& value)
298 value = o->GetUniqueID();
300 //_____________________________________________________________________
301 void AliForwardUtil::GetParameter(TObject* o, Int_t& value)
304 value = o->GetUniqueID();
306 //_____________________________________________________________________
307 void AliForwardUtil::GetParameter(TObject* o, Double_t& value)
310 UInt_t i = o->GetUniqueID();
311 Float_t v = *reinterpret_cast<Float_t*>(&i);
314 //_____________________________________________________________________
315 void AliForwardUtil::GetParameter(TObject* o, Bool_t& value)
318 value = o->GetUniqueID();
321 //_____________________________________________________________________
322 Double_t AliForwardUtil::GetStripR(Char_t ring, UShort_t strip)
325 const Double_t iMinR = 4.5213;
326 const Double_t iMaxR = 17.2;
327 const Double_t oMinR = 15.4;
328 const Double_t oMaxR = 28.0;
330 Double_t minR = (ring == 'I' || ring == 'i') ? iMinR : oMinR;
331 Double_t maxR = (ring == 'I' || ring == 'i') ? iMaxR : oMaxR;
332 Double_t nStrips = (ring == 'I' || ring == 'i') ? 512 : 256;
333 Double_t rad = maxR - minR;
334 Double_t segment = rad / nStrips;
335 Double_t r = minR + segment*strip;
340 //_____________________________________________________________________
341 Double_t AliForwardUtil::GetEtaFromStrip(UShort_t det, Char_t ring,
342 UShort_t sec, UShort_t strip,
345 // Calculate eta from strip with vertex (redundant with
346 // AliESDFMD::Eta but support displaced vertices)
349 Double_t r = GetStripR(ring, strip);
350 Int_t hybrid = sec / 2;
351 Bool_t inner = (ring == 'I' || ring == 'i');
354 case 1: z = 320.266; break;
355 case 2: z = (inner ? 83.666 : 74.966); break;
356 case 3: z = (inner ? -63.066 : -74.966); break;
357 default: return -999999;
359 if ((hybrid % 2) == 0) z -= .5;
361 Double_t theta = TMath::ATan2(r,z-zvtx);
362 Double_t eta = -1*TMath::Log(TMath::Tan(0.5*theta));
367 //_____________________________________________________________________
368 Double_t AliForwardUtil::GetPhiFromStrip(Char_t ring, UShort_t strip,
370 Double_t xvtx, Double_t yvtx)
372 // Calculate eta from strip with vertex (redundant with
373 // AliESDFMD::Eta but support displaced vertices)
375 // Unknown x,y -> no change
376 if (yvtx > 999 || xvtx > 999) return phi;
379 Double_t r = GetStripR(ring, strip);
380 Double_t amp = TMath::Sqrt(xvtx*xvtx+yvtx*yvtx) / r;
381 Double_t pha = (TMath::Abs(yvtx) < 1e-12 ? 0 : TMath::ATan2(xvtx, yvtx));
382 Double_t cha = amp * TMath::Cos(phi+pha);
384 if (phi < 0) phi += TMath::TwoPi();
385 if (phi > TMath::TwoPi()) phi -= TMath::TwoPi();
389 //====================================================================
390 Int_t AliForwardUtil::fgConvolutionSteps = 100;
391 Double_t AliForwardUtil::fgConvolutionNSigma = 5;
394 // The shift of the most probable value for the ROOT function TMath::Landau
396 const Double_t mpshift = -0.22278298;
398 // Integration normalisation
400 const Double_t invSq2pi = 1. / TMath::Sqrt(2*TMath::Pi());
403 // Utility function to use in TF1 defintition
405 Double_t landauGaus1(Double_t* xp, Double_t* pp)
408 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
409 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
410 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
411 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
412 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
414 return constant * AliForwardUtil::LandauGaus(x, delta, xi, sigma, sigmaN);
418 // Utility function to use in TF1 defintition
420 Double_t landauGausN(Double_t* xp, Double_t* pp)
423 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
424 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
425 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
426 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
427 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
428 Int_t n = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
429 Double_t* a = &(pp[AliForwardUtil::ELossFitter::kA]);
431 return constant * AliForwardUtil::NLandauGaus(x, delta, xi, sigma, sigmaN,
435 // Utility function to use in TF1 defintition
437 Double_t landauGausI(Double_t* xp, Double_t* pp)
440 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
441 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
442 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
443 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
444 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
445 Int_t i = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
447 return constant * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
452 //____________________________________________________________________
454 AliForwardUtil::Landau(Double_t x, Double_t delta, Double_t xi)
457 // Calculate the shifted Landau
459 // f'_{L}(x;\Delta,\xi) = f_L(x;\Delta+0.22278298\xi)
462 // where @f$ f_{L}@f$ is the ROOT implementation of the Landau
463 // distribution (known to have @f$ \Delta_{p}=-0.22278298@f$ for
464 // @f$\Delta=0,\xi=1@f$.
467 // x Where to evaluate @f$ f'_{L}@f$
468 // delta Most probable value
469 // xi The 'width' of the distribution
472 // @f$ f'_{L}(x;\Delta,\xi) @f$
474 return TMath::Landau(x, delta - xi * mpshift, xi);
476 //____________________________________________________________________
478 AliForwardUtil::LandauGaus(Double_t x, Double_t delta, Double_t xi,
479 Double_t sigma, Double_t sigmaN)
482 // Calculate the value of a Landau convolved with a Gaussian
485 // f(x;\Delta,\xi,\sigma') = \frac{1}{\sigma' \sqrt{2 \pi}}
486 // \int_{-\infty}^{+\infty} d\Delta' f'_{L}(x;\Delta',\xi)
487 // \exp{-\frac{(\Delta-\Delta')^2}{2\sigma'^2}}
490 // where @f$ f'_{L}@f$ is the Landau distribution, @f$ \Delta@f$ the
491 // energy loss, @f$ \xi@f$ the width of the Landau, and
492 // @f$ \sigma'^2=\sigma^2-\sigma_n^2 @f$. Here, @f$\sigma@f$ is the
493 // variance of the Gaussian, and @f$\sigma_n@f$ is a parameter modelling
494 // noise in the detector.
496 // Note that this function uses the constants fgConvolutionSteps and
497 // fgConvolutionNSigma
500 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
501 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
502 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
505 // x where to evaluate @f$ f@f$
506 // delta @f$ \Delta@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
507 // xi @f$ \xi@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
508 // sigma @f$ \sigma@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
509 // sigma_n @f$ \sigma_n@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
512 // @f$ f@f$ evaluated at @f$ x@f$.
514 Double_t deltap = delta - xi * mpshift;
515 Double_t sigma2 = sigmaN*sigmaN + sigma*sigma;
516 Double_t sigma1 = sigmaN == 0 ? sigma : TMath::Sqrt(sigma2);
517 Double_t xlow = x - fgConvolutionNSigma * sigma1;
518 Double_t xhigh = x + fgConvolutionNSigma * sigma1;
519 Double_t step = (xhigh - xlow) / fgConvolutionSteps;
522 for (Int_t i = 0; i <= fgConvolutionSteps/2; i++) {
523 Double_t x1 = xlow + (i - .5) * step;
524 Double_t x2 = xhigh - (i - .5) * step;
526 sum += TMath::Landau(x1, deltap, xi, kTRUE) * TMath::Gaus(x, x1, sigma1);
527 sum += TMath::Landau(x2, deltap, xi, kTRUE) * TMath::Gaus(x, x2, sigma1);
529 return step * sum * invSq2pi / sigma1;
532 //____________________________________________________________________
534 AliForwardUtil::ILandauGaus(Double_t x, Double_t delta, Double_t xi,
535 Double_t sigma, Double_t sigmaN, Int_t i)
540 // f_i(x;\Delta,\xi,\sigma') = f(x;\Delta_i,\xi_i,\sigma_i')
542 // corresponding to @f$ i@f$ particles i.e., with the substitutions
544 // \Delta \rightarrow \Delta_i &=& i(\Delta + \xi\log(i))
545 // \xi \rightarrow \xi_i &=& i \xi
546 // \sigma \rightarrow \sigma_i &=& \sqrt{i}\sigma
547 // \sigma'^2 \rightarrow \sigma_i'^2 &=& \sigma_n^2 + \sigma_i^2
551 // x Where to evaluate
552 // delta @f$ \Delta@f$
554 // sigma @f$ \sigma@f$
555 // sigma_n @f$ \sigma_n@f$
559 // @f$ f_i @f$ evaluated
561 Double_t deltaI = (i == 1 ? delta : i * (delta + xi * TMath::Log(i)));
562 Double_t xiI = i * xi;
563 Double_t sigmaI = (i == 1 ? sigma : TMath::Sqrt(Double_t(i))*sigma);
564 if (sigmaI < 1e-10) {
565 // Fall back to landau
566 return AliForwardUtil::Landau(x, deltaI, xiI);
568 return AliForwardUtil::LandauGaus(x, deltaI, xiI, sigmaI, sigmaN);
571 //____________________________________________________________________
573 AliForwardUtil::IdLandauGausdPar(Double_t x,
574 UShort_t par, Double_t dPar,
575 Double_t delta, Double_t xi,
576 Double_t sigma, Double_t sigmaN,
580 // Numerically evaluate
582 // \left.\frac{\partial f_i}{\partial p_i}\right|_{x}
584 // where @f$ p_i@f$ is the @f$ i^{\mbox{th}}@f$ parameter. The mapping
585 // of the parameters is given by
590 // - 3: @f$\sigma_n@f$
592 // This is the partial derivative with respect to the parameter of
593 // the response function corresponding to @f$ i@f$ particles i.e.,
594 // with the substitutions
596 // \Delta \rightarrow \Delta_i = i(\Delta + \xi\log(i))
597 // \xi \rightarrow \xi_i = i \xi
598 // \sigma \rightarrow \sigma_i = \sqrt{i}\sigma
599 // \sigma'^2 \rightarrow \sigma_i'^2 = \sigma_n^2 + \sigma_i^2
603 // x Where to evaluate
604 // ipar Parameter number
605 // dp @f$ \epsilon\delta p_i@f$ for some value of @f$\epsilon@f$
606 // delta @f$ \Delta@f$
608 // sigma @f$ \sigma@f$
609 // sigma_n @f$ \sigma_n@f$
613 // @f$ f_i@f$ evaluated
615 if (dPar == 0) return 0;
617 Double_t d2 = dPar / 2;
618 Double_t deltaI = i * (delta + xi * TMath::Log(i));
619 Double_t xiI = i * xi;
620 Double_t si = TMath::Sqrt(Double_t(i));
621 Double_t sigmaI = si*sigma;
628 y1 = ILandauGaus(x, deltaI+i*dp, xiI, sigmaI, sigmaN, i);
629 y2 = ILandauGaus(x, deltaI+i*d2, xiI, sigmaI, sigmaN, i);
630 y3 = ILandauGaus(x, deltaI-i*d2, xiI, sigmaI, sigmaN, i);
631 y4 = ILandauGaus(x, deltaI-i*dp, xiI, sigmaI, sigmaN, i);
634 y1 = ILandauGaus(x, deltaI, xiI+i*dp, sigmaI, sigmaN, i);
635 y2 = ILandauGaus(x, deltaI, xiI+i*d2, sigmaI, sigmaN, i);
636 y3 = ILandauGaus(x, deltaI, xiI-i*d2, sigmaI, sigmaN, i);
637 y4 = ILandauGaus(x, deltaI, xiI-i*dp, sigmaI, sigmaN, i);
640 y1 = ILandauGaus(x, deltaI, xiI, sigmaI+si*dp, sigmaN, i);
641 y2 = ILandauGaus(x, deltaI, xiI, sigmaI+si*d2, sigmaN, i);
642 y3 = ILandauGaus(x, deltaI, xiI, sigmaI-si*d2, sigmaN, i);
643 y4 = ILandauGaus(x, deltaI, xiI, sigmaI-si*dp, sigmaN, i);
646 y1 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+dp, i);
647 y2 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+d2, i);
648 y3 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-d2, i);
649 y4 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-dp, i);
655 Double_t d0 = y1 - y4;
656 Double_t d1 = 2 * (y2 - y3);
658 Double_t g = 1/(2*dp) * (4*d1 - d0) / 3;
663 //____________________________________________________________________
665 AliForwardUtil::NLandauGaus(Double_t x, Double_t delta, Double_t xi,
666 Double_t sigma, Double_t sigmaN, Int_t n,
672 // f_N(x;\Delta,\xi,\sigma') = \sum_{i=1}^N a_i f_i(x;\Delta,\xi,\sigma'a)
675 // where @f$ f(x;\Delta,\xi,\sigma')@f$ is the convolution of a
676 // Landau with a Gaussian (see LandauGaus). Note that
677 // @f$ a_1 = 1@f$, @f$\Delta_i = i(\Delta_1 + \xi\log(i))@f$,
678 // @f$\xi_i=i\xi_1@f$, and @f$\sigma_i'^2 = \sigma_n^2 + i\sigma_1^2@f$.
681 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
682 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
683 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
686 // x Where to evaluate @f$ f_N@f$
687 // delta @f$ \Delta_1@f$
689 // sigma @f$ \sigma_1@f$
690 // sigma_n @f$ \sigma_n@f$
691 // n @f$ N@f$ in the sum above.
692 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
696 // @f$ f_N(x;\Delta,\xi,\sigma')@f$
698 Double_t result = ILandauGaus(x, delta, xi, sigma, sigmaN, 1);
699 for (Int_t i = 2; i <= n; i++)
700 result += a[i-2] * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
704 const Int_t kColors[] = { kRed+1,
718 //____________________________________________________________________
720 AliForwardUtil::MakeNLandauGaus(Double_t c,
721 Double_t delta, Double_t xi,
722 Double_t sigma, Double_t sigmaN, Int_t n,
724 Double_t xmin, Double_t xmax)
727 // Generate a TF1 object of @f$ f_N@f$
731 // delta @f$ \Delta@f$
733 // sigma @f$ \sigma_1@f$
734 // sigma_n @f$ \sigma_n@f$
735 // n @f$ N@f$ - how many particles to sum to
736 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
738 // xmin Least value of range
739 // xmax Largest value of range
742 // Newly allocated TF1 object
744 Int_t npar = AliForwardUtil::ELossFitter::kN+n;
745 TF1* landaun = new TF1(Form("nlandau%d", n), &landauGausN,xmin,xmax,npar);
746 // landaun->SetLineStyle(((n-2) % 10)+2); // start at dashed
747 landaun->SetLineColor(kColors[((n-1) % 12)]); // start at red
748 landaun->SetLineWidth(2);
749 landaun->SetNpx(500);
750 landaun->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "N");
752 // Set the initial parameters from the seed fit
753 landaun->SetParameter(AliForwardUtil::ELossFitter::kC, c);
754 landaun->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
755 landaun->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
756 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
757 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
758 landaun->FixParameter(AliForwardUtil::ELossFitter::kN, n);
760 // Set the range and name of the scale parameters
761 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
762 landaun->SetParameter(AliForwardUtil::ELossFitter::kA+i-2, a[i-2]);
763 landaun->SetParName(AliForwardUtil::ELossFitter::kA+i-2, Form("a_{%d}", i));
767 //____________________________________________________________________
769 AliForwardUtil::MakeILandauGaus(Double_t c,
770 Double_t delta, Double_t xi,
771 Double_t sigma, Double_t sigmaN, Int_t i,
772 Double_t xmin, Double_t xmax)
775 // Generate a TF1 object of @f$ f_I@f$
779 // delta @f$ \Delta@f$
781 // sigma @f$ \sigma_1@f$
782 // sigma_n @f$ \sigma_n@f$
783 // i @f$ i@f$ - the number of particles
784 // xmin Least value of range
785 // xmax Largest value of range
788 // Newly allocated TF1 object
790 Int_t npar = AliForwardUtil::ELossFitter::kN+1;
791 TF1* landaui = new TF1(Form("ilandau%d", i), &landauGausI,xmin,xmax,npar);
792 // landaui->SetLineStyle(((i-2) % 10)+2); // start at dashed
793 landaui->SetLineColor(kColors[((i-1) % 12)]); // start at red
794 landaui->SetLineWidth(1);
795 landaui->SetNpx(500);
796 landaui->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "i");
798 // Set the initial parameters from the seed fit
799 landaui->SetParameter(AliForwardUtil::ELossFitter::kC, c);
800 landaui->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
801 landaui->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
802 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
803 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
804 landaui->FixParameter(AliForwardUtil::ELossFitter::kN, i);
809 //====================================================================
810 AliForwardUtil::ELossFitter::ELossFitter(Double_t lowCut,
813 : fLowCut(lowCut), fMaxRange(maxRange), fMinusBins(minusBins),
814 fFitResults(0), fFunctions(0)
820 // lowCut Lower cut of spectrum - data below this cuts is ignored
821 // maxRange Maximum range to fit to
822 // minusBins The number of bins below maximum to use
824 fFitResults.SetOwner();
825 fFunctions.SetOwner();
827 //____________________________________________________________________
828 AliForwardUtil::ELossFitter::~ELossFitter()
834 fFitResults.Delete();
837 //____________________________________________________________________
839 AliForwardUtil::ELossFitter::Clear()
842 // Clear internal arrays
848 //____________________________________________________________________
850 AliForwardUtil::ELossFitter::Fit1Particle(TH1* dist, Double_t sigman)
853 // Fit a 1-particle signal to the passed energy loss distribution
855 // Note that this function clears the internal arrays first
858 // dist Data to fit the function to
859 // sigman If larger than zero, the initial guess of the
860 // detector induced noise. If zero or less, then this
861 // parameter is ignored in the fit (fixed at 0)
864 // The function fitted to the data
870 // Find the fit range
871 dist->GetXaxis()->SetRangeUser(fLowCut, fMaxRange);
873 // Get the bin with maximum
874 Int_t maxBin = dist->GetMaximumBin();
875 Double_t maxE = dist->GetBinLowEdge(maxBin);
878 dist->GetXaxis()->SetRangeUser(fLowCut, maxE);
879 Int_t minBin = maxBin - fMinusBins; // dist->GetMinimumBin();
880 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
881 Double_t maxEE = dist->GetBinCenter(maxBin+2*fMinusBins);
884 dist->GetXaxis()->SetRangeUser(0, fMaxRange);
886 // Define the function to fit
887 TF1* landau1 = new TF1("landau1", landauGaus1, minE,maxEE,kSigmaN+1);
889 // Set initial guesses, parameter names, and limits
890 landau1->SetParameters(1,0.5,0.07,0.1,sigman);
891 landau1->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
892 landau1->SetNpx(500);
893 landau1->SetParLimits(kDelta, minE, fMaxRange);
894 landau1->SetParLimits(kXi, 0.00, fMaxRange);
895 landau1->SetParLimits(kSigma, 0.01, 0.1);
896 if (sigman <= 0) landau1->FixParameter(kSigmaN, 0);
897 else landau1->SetParLimits(kSigmaN, 0, fMaxRange);
899 // Do the fit, getting the result object
900 TFitResultPtr r = dist->Fit(landau1, "RNQS", "", minE, maxEE);
901 landau1->SetRange(minE, fMaxRange);
902 fFitResults.AddAtAndExpand(new TFitResult(*r), 0);
903 fFunctions.AddAtAndExpand(landau1, 0);
907 //____________________________________________________________________
909 AliForwardUtil::ELossFitter::FitNParticle(TH1* dist, UShort_t n,
913 // Fit a N-particle signal to the passed energy loss distribution
915 // If there's no 1-particle fit present, it does that first
918 // dist Data to fit the function to
919 // n Number of particle signals to fit
920 // sigman If larger than zero, the initial guess of the
921 // detector induced noise. If zero or less, then this
922 // parameter is ignored in the fit (fixed at 0)
925 // The function fitted to the data
928 // Get the seed fit result
929 TFitResult* r = static_cast<TFitResult*>(fFitResults.At(0));
930 TF1* f = static_cast<TF1*>(fFunctions.At(0));
932 f = Fit1Particle(dist, sigman);
933 r = static_cast<TFitResult*>(fFitResults.At(0));
935 ::Warning("FitNLandau", "No first shot at landau fit");
940 // Get some parameters from seed fit
941 Double_t delta1 = r->Parameter(kDelta);
942 Double_t xi1 = r->Parameter(kXi);
943 Double_t maxEi = n * (delta1 + xi1 * TMath::Log(n)) + 2 * n * xi1;
944 Double_t minE = f->GetXmin();
948 for (UShort_t i = 2; i <= n; i++)
949 a.fArray[i-2] = (n == 2 ? 0.05 : 0.000001);
950 // Make the fit function
951 TF1* landaun = MakeNLandauGaus(r->Parameter(kC),
952 r->Parameter(kDelta),
954 r->Parameter(kSigma),
955 r->Parameter(kSigmaN),
956 n,a.fArray,minE,maxEi);
957 landaun->SetParLimits(kDelta, minE, fMaxRange); // Delta
958 landaun->SetParLimits(kXi, 0.00, fMaxRange); // xi
959 landaun->SetParLimits(kSigma, 0.01, 1); // sigma
960 // Check if we're using the noise sigma
961 if (sigman <= 0) landaun->FixParameter(kSigmaN, 0);
962 else landaun->SetParLimits(kSigmaN, 0, fMaxRange);
964 // Set the range and name of the scale parameters
965 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
966 landaun->SetParLimits(kA+i-2, 0,1);
970 TFitResultPtr tr = dist->Fit(landaun, "RSQN", "", minE, maxEi);
972 landaun->SetRange(minE, fMaxRange);
973 fFitResults.AddAtAndExpand(new TFitResult(*tr), n-1);
974 fFunctions.AddAtAndExpand(landaun, n-1);
979 //====================================================================
980 AliForwardUtil::Histos::~Histos()
987 //____________________________________________________________________
989 AliForwardUtil::Histos::Delete(Option_t* opt)
991 if (fFMD1i) delete fFMD1i;
992 if (fFMD2i) delete fFMD2i;
993 if (fFMD2o) delete fFMD2o;
994 if (fFMD3i) delete fFMD3i;
995 if (fFMD3o) delete fFMD3o;
1001 TObject::Delete(opt);
1004 //____________________________________________________________________
1006 AliForwardUtil::Histos::Make(UShort_t d, Char_t r,
1007 const TAxis& etaAxis) const
1015 // etaAxis Eta axis to use
1018 // Newly allocated histogram
1020 Int_t ns = (r == 'I' || r == 'i') ? 20 : 40;
1021 TH2D* hist = new TH2D(Form("FMD%d%c_cache", d, r),
1022 Form("FMD%d%c cache", d, r),
1023 etaAxis.GetNbins(), etaAxis.GetXmin(),
1024 etaAxis.GetXmax(), ns, 0, 2*TMath::Pi());
1025 hist->SetXTitle("#eta");
1026 hist->SetYTitle("#phi [radians]");
1027 hist->SetZTitle("d^{2}N_{ch}/d#etad#phi");
1029 hist->SetDirectory(0);
1033 //____________________________________________________________________
1035 AliForwardUtil::Histos::Init(const TAxis& etaAxis)
1038 // Initialize the object
1041 // etaAxis Eta axis to use
1043 fFMD1i = Make(1, 'I', etaAxis);
1044 fFMD2i = Make(2, 'I', etaAxis);
1045 fFMD2o = Make(2, 'O', etaAxis);
1046 fFMD3i = Make(3, 'I', etaAxis);
1047 fFMD3o = Make(3, 'O', etaAxis);
1049 //____________________________________________________________________
1051 AliForwardUtil::Histos::Clear(Option_t* option)
1059 if (fFMD1i) fFMD1i->Reset(option);
1060 if (fFMD2i) fFMD2i->Reset(option);
1061 if (fFMD2o) fFMD2o->Reset(option);
1062 if (fFMD3i) fFMD3i->Reset(option);
1063 if (fFMD3o) fFMD3o->Reset(option);
1066 //____________________________________________________________________
1068 AliForwardUtil::Histos::Get(UShort_t d, Char_t r) const
1071 // Get the histogram for a particular detector,ring
1078 // Histogram for detector,ring or nul
1081 case 1: return fFMD1i;
1082 case 2: return (r == 'I' || r == 'i' ? fFMD2i : fFMD2o);
1083 case 3: return (r == 'I' || r == 'i' ? fFMD3i : fFMD3o);
1087 //====================================================================
1089 AliForwardUtil::RingHistos::DefineOutputList(TList* d) const
1092 // Define the outout list in @a d
1095 // d Where to put the output list
1098 // Newly allocated TList object or null
1101 TList* list = new TList;
1103 list->SetName(fName.Data());
1107 //____________________________________________________________________
1109 AliForwardUtil::RingHistos::GetOutputList(const TList* d) const
1112 // Get our output list from the container @a d
1115 // d where to get the output list from
1118 // The found TList or null
1121 TList* list = static_cast<TList*>(d->FindObject(fName.Data()));
1125 //____________________________________________________________________
1127 AliForwardUtil::RingHistos::GetOutputHist(const TList* d, const char* name) const
1130 // Find a specific histogram in the source list @a d
1133 // d (top)-container
1134 // name Name of histogram
1137 // Found histogram or null
1139 return static_cast<TH1*>(d->FindObject(name));
1142 //====================================================================
1143 AliForwardUtil::DebugGuard::DebugGuard(Int_t lvl, Int_t msgLvl,
1144 const char* format, ...)
1147 if (lvl < msgLvl) return;
1149 va_start(ap, format);
1150 Format(fMsg, format, ap);
1154 //____________________________________________________________________
1155 AliForwardUtil::DebugGuard::~DebugGuard()
1157 if (fMsg.IsNull()) return;
1160 //____________________________________________________________________
1162 AliForwardUtil::DebugGuard::Message(Int_t lvl, Int_t msgLvl,
1163 const char* format, ...)
1165 if (lvl < msgLvl) return;
1168 va_start(ap, format);
1169 Format(msg, format, ap);
1174 //____________________________________________________________________
1176 AliForwardUtil::DebugGuard::Format(TString& out, const char* format, va_list ap)
1178 static char buf[512];
1179 Int_t n = gROOT->GetDirLevel() + 2;
1180 for (Int_t i = 0; i < n; i++) buf[i] = ' ';
1181 vsnprintf(&(buf[n]), 511-n, format, ap);
1185 //____________________________________________________________________
1187 AliForwardUtil::DebugGuard::Output(int in, TString& msg)
1189 msg[0] = (in > 0 ? '>' : in < 0 ? '<' : '=');
1190 AliLog::Message(AliLog::kInfo, msg, 0, 0, "PWGLF/forward", 0, 0);
1191 if (in > 0) gROOT->IncreaseDirLevel();
1192 else if (in < 0) gROOT->DecreaseDirLevel();