2 // Utilities used in the forward multiplcity analysis
5 #include "AliForwardUtil.h"
6 //#include <ARVersion.h>
7 #include <AliAnalysisManager.h>
8 #include "AliAODForwardMult.h"
10 #include <AliInputEventHandler.h>
11 #include <AliAODInputHandler.h>
12 #include <AliAODHandler.h>
13 #include <AliAODEvent.h>
14 #include <AliESDEvent.h>
15 #include <AliAnalysisTaskSE.h>
16 #include <AliPhysicsSelection.h>
17 #include <AliTriggerAnalysis.h>
18 #include <AliMultiplicity.h>
19 #include <TParameter.h>
23 #include <TFitResult.h>
27 #define FIT_OPTIONS "RNS"
29 //====================================================================
30 ULong_t AliForwardUtil::AliROOTRevision()
32 #ifdef ALIROOT_SVN_REVISION
33 return ALIROOT_SVN_REVISION;
34 #elif defined(ALIROOT_REVISION)
35 static ULong_t ret = 0;
36 if (ret != 0) return ret;
38 // Select first 32bits of the 40byte long check-sum
39 TString rev(ALIROOT_REVISION, 8);
40 for (ULong_t i = 0; i < 8; i++) {
43 case '0': p = 0; break;
44 case '1': p = 1; break;
45 case '2': p = 2; break;
46 case '3': p = 3; break;
47 case '4': p = 4; break;
48 case '5': p = 5; break;
49 case '6': p = 6; break;
50 case '7': p = 7; break;
51 case '8': p = 8; break;
52 case '9': p = 9; break;
53 case 'a': case 'A': p = 10; break;
54 case 'b': case 'B': p = 11; break;
55 case 'c': case 'C': p = 12; break;
56 case 'd': case 'D': p = 13; break;
57 case 'e': case 'E': p = 14; break;
58 case 'f': case 'F': p = 15; break;
60 ret |= (p << (32-4*(i+1)));
67 //____________________________________________________________________
68 ULong_t AliForwardUtil::AliROOTBranch()
70 // Do something here when we switch to git - sigh!
71 #if !defined(ALIROOT_SVN_BRANCH) && !defined(ALIROOT_BRANCH)
74 static ULong_t ret = 0;
75 if (ret != 0) return ret;
78 #ifdef ALIROOT_SVN_BRANCH
79 str = ALIROOT_SVN_BRANCH;
81 #elif defined(ALIROOT_BRANCH)
85 if (str.IsNull()) return 0xFFFFFFFF;
86 if (str[0] == 'v') str.Remove(0,1);
87 if (str.EqualTo(top)) return ret = 0xFFFFFFFF;
89 TObjArray* tokens = str.Tokenize("-");
90 TObjString* pMajor = tokens->GetEntries()>0 ?
91 (static_cast<TObjString*>(tokens->At(0))) : 0;
92 TObjString* pMinor = tokens->GetEntries()>1 ?
93 (static_cast<TObjString*>(tokens->At(1))) : 0;
94 TObjString* pRelea = tokens->GetEntries() > 2 ?
95 static_cast<TObjString*>(tokens->At(2)) : 0;
96 TObjString* pAn = tokens->GetEntries() > 3 ?
97 static_cast<TObjString*>(tokens->At(3)) : 0;
98 TString sMajor,sMinor,sRelea;
99 if (pMajor) sMajor = pMajor->String().Strip(TString::kLeading, '0');
100 if (pMinor) sMinor = pMinor->String().Strip(TString::kLeading, '0');
101 if (pRelea) sRelea = pRelea->String().Strip(TString::kLeading, '0');
103 ret = (((sMajor.Atoi() & 0xFF) << 12) |
104 ((sMinor.Atoi() & 0xFF) << 8) |
105 ((sRelea.Atoi() & 0xFF) << 4) |
111 //====================================================================
113 AliForwardUtil::ParseCollisionSystem(const char* sys)
116 // Parse a collision system spec given in a string. Known values are
118 // - "ppb", "p-pb", "pa", "p-a" which returns kPPb
119 // - "pp", "p-p" which returns kPP
120 // - "PbPb", "Pb-Pb", "A-A", which returns kPbPb
121 // - Everything else gives kUnknown
124 // sys Collision system spec
127 // Collision system id
131 // we do pA first to avoid pp catch on ppb string (AH)
132 if (s.Contains("p-pb") || s.Contains("ppb")) return AliForwardUtil::kPPb;
133 if (s.Contains("p-a") || s.Contains("pa")) return AliForwardUtil::kPPb;
134 if (s.Contains("a-p") || s.Contains("ap")) return AliForwardUtil::kPPb;
135 if (s.Contains("p-p") || s.Contains("pp")) return AliForwardUtil::kPP;
136 if (s.Contains("pb-pb") || s.Contains("pbpb")) return AliForwardUtil::kPbPb;
137 if (s.Contains("a-a") || s.Contains("aa")) return AliForwardUtil::kPbPb;
138 return AliForwardUtil::kUnknown;
140 //____________________________________________________________________
142 AliForwardUtil::CollisionSystemString(UShort_t sys)
145 // Get a string representation of the collision system
148 // sys Collision system
151 // - anything else gives "unknown"
154 // String representation of the collision system
157 case AliForwardUtil::kPP: return "pp";
158 case AliForwardUtil::kPbPb: return "PbPb";
159 case AliForwardUtil::kPPb: return "pPb";
163 //____________________________________________________________________
165 AliForwardUtil::BeamRapidity(Float_t beam, UShort_t z, UShort_t a)
167 const Double_t pMass = 9.38271999999999995e-01;
168 const Double_t nMass = 9.39564999999999984e-01;
169 Double_t beamE = z * beam / 2;
170 Double_t beamM = z * pMass + (a - z) * nMass;
171 Double_t beamP = TMath::Sqrt(beamE * beamE - beamM * beamM);
172 Double_t beamY = .5* TMath::Log((beamE+beamP) / (beamE-beamP));
175 //____________________________________________________________________
177 AliForwardUtil::CenterOfMassEnergy(Float_t beam,
183 // Calculate the center of mass energy given target/projectile
184 // mass and charge numbers
187 return TMath::Sqrt(Float_t(z1*z2)/a1/a2) * beam;
189 //____________________________________________________________________
191 AliForwardUtil::CenterOfMassRapidity(UShort_t z1,
196 // Calculate the center of mass rapidity (shift) given target/projectile
197 // mass and charge numbers
200 if (z2 == z1 && a2 == a1) return 0;
201 return .5 * TMath::Log(Float_t(z1*a2)/z2/a1);
205 UShort_t CheckSNN(Float_t energy)
207 if (TMath::Abs(energy - 900.) < 10) return 900;
208 if (TMath::Abs(energy - 2400.) < 10) return 2400;
209 if (TMath::Abs(energy - 2760.) < 20) return 2760;
210 if (TMath::Abs(energy - 4400.) < 10) return 4400;
211 if (TMath::Abs(energy - 5022.) < 10) return 5023;
212 if (TMath::Abs(energy - 5500.) < 40) return 5500;
213 if (TMath::Abs(energy - 7000.) < 10) return 7000;
214 if (TMath::Abs(energy - 8000.) < 10) return 8000;
215 if (TMath::Abs(energy - 10000.) < 10) return 10000;
216 if (TMath::Abs(energy - 14000.) < 10) return 14000;
220 //____________________________________________________________________
222 AliForwardUtil::ParseCenterOfMassEnergy(UShort_t sys, Float_t beam)
225 // Parse the center of mass energy given as a float and return known
226 // values as a unsigned integer
229 // sys Collision system (needed for AA)
230 // beam Center of mass energy * total charge
233 // Center of mass energy per nucleon
235 Float_t energy = beam;
236 // Below no longer needed apparently
237 // if (sys == AliForwardUtil::kPbPb) energy = energy / 208 * 82;
238 if (sys == AliForwardUtil::kPPb)
239 energy = CenterOfMassEnergy(beam, 82, 208, 1, 1);
240 else if (sys == AliForwardUtil::kPbPb)
241 energy = CenterOfMassEnergy(beam, 82, 208, 82, 208);
242 UShort_t ret = CheckSNN(energy);
243 if (ret > 1) return ret;
244 if (sys == AliForwardUtil::kPbPb || sys == AliForwardUtil::kPPb) {
245 ret = CheckSNN(beam);
249 //____________________________________________________________________
251 AliForwardUtil::CenterOfMassEnergyString(UShort_t cms)
254 // Get a string representation of the center of mass energy per nuclean
257 // cms Center of mass energy per nucleon
260 // String representation of the center of mass energy per nuclean
262 return Form("%04dGeV", cms);
264 //____________________________________________________________________
266 AliForwardUtil::ParseMagneticField(Float_t v)
269 // Parse the magnetic field (in kG) as given by a floating point number
272 // field Magnetic field in kG
275 // Short integer value of magnetic field in kG
277 if (TMath::Abs(v - 5.) < 1 ) return +5;
278 if (TMath::Abs(v + 5.) < 1 ) return -5;
279 if (TMath::Abs(v) < 1) return 0;
282 //____________________________________________________________________
284 AliForwardUtil::MagneticFieldString(Short_t f)
287 // Get a string representation of the magnetic field
290 // field Magnetic field in kG
293 // String representation of the magnetic field
295 return Form("%01dkG", f);
297 //_____________________________________________________________________
298 AliAODEvent* AliForwardUtil::GetAODEvent(AliAnalysisTaskSE* task)
300 // Check if AOD is the output event
301 if (!task) ::Fatal("GetAODEvent", "Null task given, cannot do that");
303 AliAODEvent* ret = task->AODEvent();
306 // Check if AOD is the input event
307 ret = dynamic_cast<AliAODEvent*>(task->InputEvent());
308 if (!ret) ::Warning("GetAODEvent", "No AOD event found");
312 //_____________________________________________________________________
313 UShort_t AliForwardUtil::CheckForAOD()
315 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
316 if (dynamic_cast<AliAODInputHandler*>(am->GetInputEventHandler())) {
317 // ::Info("CheckForAOD", "Found AOD Input handler");
320 if (dynamic_cast<AliAODHandler*>(am->GetOutputEventHandler())) {
321 // ::Info("CheckForAOD", "Found AOD Output handler");
325 ::Warning("CheckForAOD",
326 "Neither and input nor output AOD handler is specified");
329 //_____________________________________________________________________
330 Bool_t AliForwardUtil::CheckForTask(const char* clsOrName, Bool_t cls)
332 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
334 AliAnalysisTask* t = am->GetTask(clsOrName);
336 ::Warning("CheckForTask", "Task %s not found in manager", clsOrName);
339 ::Info("CheckForTask", "Found task %s", clsOrName);
342 TClass* dep = gROOT->GetClass(clsOrName);
344 ::Warning("CheckForTask", "Unknown class %s for needed task", clsOrName);
347 TIter next(am->GetTasks());
349 while ((o = next())) {
350 if (o->IsA()->InheritsFrom(dep)) {
351 ::Info("CheckForTask", "Found task of class %s: %s",
352 clsOrName, o->GetName());
356 ::Warning("CheckForTask", "No task of class %s was found", clsOrName);
360 //_____________________________________________________________________
361 TObject* AliForwardUtil::MakeParameter(const Char_t* name, UShort_t value)
363 TParameter<int>* ret = new TParameter<int>(name, value);
364 ret->SetMergeMode('f');
365 ret->SetUniqueID(value);
368 //_____________________________________________________________________
369 TObject* AliForwardUtil::MakeParameter(const Char_t* name, Int_t value)
371 TParameter<int>* ret = new TParameter<int>(name, value);
372 ret->SetMergeMode('f');
373 ret->SetUniqueID(value);
376 //_____________________________________________________________________
377 TObject* AliForwardUtil::MakeParameter(const Char_t* name, ULong_t value)
379 TParameter<Long_t>* ret = new TParameter<Long_t>(name, value);
380 ret->SetMergeMode('f');
381 ret->SetUniqueID(value);
384 //_____________________________________________________________________
385 TObject* AliForwardUtil::MakeParameter(const Char_t* name, Double_t value)
387 TParameter<double>* ret = new TParameter<double>(name, value);
388 // Float_t v = value;
389 // UInt_t* tmp = reinterpret_cast<UInt_t*>(&v);
390 ret->SetMergeMode('f');
391 // ret->SetUniqueID(*tmp);
394 //_____________________________________________________________________
395 TObject* AliForwardUtil::MakeParameter(const Char_t* name, Bool_t value)
397 TParameter<bool>* ret = new TParameter<bool>(name, value);
398 ret->SetMergeMode('f');
399 ret->SetUniqueID(value);
403 //_____________________________________________________________________
404 void AliForwardUtil::GetParameter(TObject* o, UShort_t& value)
407 TParameter<int>* p = static_cast<TParameter<int>*>(o);
408 if (p->TestBit(BIT(19)))
411 value = o->GetUniqueID();
413 //_____________________________________________________________________
414 void AliForwardUtil::GetParameter(TObject* o, Int_t& value)
417 TParameter<int>* p = static_cast<TParameter<int>*>(o);
418 if (p->TestBit(BIT(19)))
421 value = o->GetUniqueID();
423 //_____________________________________________________________________
424 void AliForwardUtil::GetParameter(TObject* o, ULong_t& value)
427 TParameter<Long_t>* p = static_cast<TParameter<Long_t>*>(o);
428 if (p->TestBit(BIT(19)))
431 value = o->GetUniqueID();
433 //_____________________________________________________________________
434 void AliForwardUtil::GetParameter(TObject* o, Double_t& value)
437 TParameter<double>* p = static_cast<TParameter<double>*>(o);
438 if (p->TestBit(BIT(19)))
439 value = p->GetVal(); // o->GetUniqueID();
441 UInt_t i = o->GetUniqueID();
442 Float_t v = *reinterpret_cast<Float_t*>(&i);
446 //_____________________________________________________________________
447 void AliForwardUtil::GetParameter(TObject* o, Bool_t& value)
450 TParameter<bool>* p = static_cast<TParameter<bool>*>(o);
451 if (p->TestBit(BIT(19)))
452 value = p->GetVal(); // o->GetUniqueID();
454 value = o->GetUniqueID();
458 //_____________________________________________________________________
459 Double_t AliForwardUtil::GetStripR(Char_t ring, UShort_t strip)
463 // Optimized version that has a cache
464 static TArrayD inner;
465 static TArrayD outer;
466 if (inner.GetSize() <= 0 || outer.GetSize() <= 0) {
467 const Double_t minR[] = { 4.5213, 15.4 };
468 const Double_t maxR[] = { 17.2, 28.0 };
469 const Int_t nStr[] = { 512, 256 };
470 for (Int_t q = 0; q < 2; q++) {
471 TArrayD& a = (q == 0 ? inner : outer);
474 for (Int_t it = 0; it < nStr[q]; it++) {
475 Double_t rad = maxR[q] - minR[q];
476 Double_t segment = rad / nStr[q];
477 Double_t r = minR[q] + segment*strip;
482 if (ring == 'I' || ring == 'i') return inner.At(strip);
483 return outer.At(strip);
486 //_____________________________________________________________________
487 Double_t AliForwardUtil::GetStripR(Char_t ring, UShort_t strip)
491 // New implementation has only one branch
492 const Double_t minR[] = { 4.5213, 15.4 };
493 const Double_t maxR[] = { 17.2, 28.0 };
494 const Int_t nStr[] = { 512, 256 };
496 Int_t q = (ring == 'I' || ring == 'i') ? 0 : 1;
497 Double_t rad = maxR[q] - minR[q];
498 Double_t segment = rad / nStr[q];
499 Double_t r = minR[q] + segment*strip;
506 //_____________________________________________________________________
507 Double_t AliForwardUtil::GetEtaFromStrip(UShort_t det, Char_t ring,
508 UShort_t sec, UShort_t strip,
511 // Calculate eta from strip with vertex (redundant with
512 // AliESDFMD::Eta but support displaced vertices)
514 // Slightly more optimized version that uses less branching
516 // Get R of the strip
517 Double_t r = GetStripR(ring, strip);
518 Int_t hybrid = sec / 2;
519 Int_t q = (ring == 'I' || ring == 'i') ? 0 : 1;
521 const Double_t zs[][2] = { { 320.266, -999999 },
523 { -63.066, -74.966 } };
524 if (det > 3 || zs[det-1][q] == -999999) return -999999;
526 Double_t z = zs[det-1][q];
527 if ((hybrid % 2) == 0) z -= .5;
529 Double_t theta = TMath::ATan2(r,z-zvtx);
530 Double_t eta = -1*TMath::Log(TMath::Tan(0.5*theta));
535 //_____________________________________________________________________
536 Double_t AliForwardUtil::GetEtaFromStrip(UShort_t det, Char_t ring,
537 UShort_t sec, UShort_t strip,
540 // Calculate eta from strip with vertex (redundant with
541 // AliESDFMD::Eta but support displaced vertices)
544 Double_t r = GetStripR(ring, strip);
545 Int_t hybrid = sec / 2;
546 Bool_t inner = (ring == 'I' || ring == 'i');
551 case 1: z = 320.266; break;
552 case 2: z = (inner ? 83.666 : 74.966); break;
553 case 3: z = (inner ? -63.066 : -74.966); break;
554 default: return -999999;
556 if ((hybrid % 2) == 0) z -= .5;
558 Double_t theta = TMath::ATan2(r,z-zvtx);
559 Double_t eta = -1*TMath::Log(TMath::Tan(0.5*theta));
565 //_____________________________________________________________________
566 Double_t AliForwardUtil::GetPhiFromStrip(Char_t ring, UShort_t strip,
568 Double_t xvtx, Double_t yvtx)
570 // Calculate eta from strip with vertex (redundant with
571 // AliESDFMD::Eta but support displaced vertices)
573 // Unknown x,y -> no change
574 if (yvtx > 999 || xvtx > 999) return phi;
577 Double_t r = GetStripR(ring, strip);
578 Double_t amp = TMath::Sqrt(xvtx*xvtx+yvtx*yvtx) / r;
579 Double_t pha = (TMath::Abs(yvtx) < 1e-12 ? 0 : TMath::ATan2(xvtx, yvtx));
580 Double_t cha = amp * TMath::Cos(phi+pha);
582 if (phi < 0) phi += TMath::TwoPi();
583 if (phi > TMath::TwoPi()) phi -= TMath::TwoPi();
586 //====================================================================
588 AliForwardUtil::MakeFullIpZAxis(Int_t nCenter)
591 MakeFullIpZAxis(nCenter, bins);
592 TAxis* a = new TAxis(bins.GetSize()-1,bins.GetArray());
595 //____________________________________________________________________
597 AliForwardUtil::MakeFullIpZAxis(Int_t nCenter, TArrayD& bins)
599 // Custom vertex axis that will include satellite vertices
600 // Satellite vertices are at k*37.5 where k=-10,-9,...,9,10
601 // Nominal vertices are usually in -10 to 10 and we should have
602 // 10 bins in that range. That gives us a total of
606 // or 31 bin boundaries
607 if (nCenter % 2 == 1)
608 // Number of central bins is odd - make it even
610 const Double_t mCenter = 20;
611 const Int_t nSat = 10;
612 const Int_t nBins = 2*nSat + nCenter;
613 const Int_t mBin = nBins / 2;
614 Double_t dCenter = 2*mCenter / nCenter;
617 for (Int_t i = 1; i <= nCenter/2; i++) {
618 // Assign from the middle out
619 Double_t v = i * dCenter;
620 // Printf("Assigning +/-%7.2f to %3d/%3d", v,mBin-i,mBin+i);
624 for (Int_t i = 1; i <= nSat; i++) {
625 Double_t v = (i+.5) * 37.5;
626 Int_t o = nCenter/2+i;
627 // Printf("Assigning +/-%7.2f to %3d/%3d", v,mBin-o,mBin+o);
632 //____________________________________________________________________
634 AliForwardUtil::MakeLogScale(Int_t nBins,
639 Double_t dO = Double_t(maxOrder-minOrder) / nBins;
641 for (Int_t i = 0; i <= nBins; i++) bins[i] = TMath::Power(10, i * dO+minOrder);
644 //____________________________________________________________________
646 AliForwardUtil::PrintTask(const TObject& o)
648 Int_t ind = gROOT->GetDirLevel();
651 std::cout << std::setfill(' ') << std::setw(ind) << " " << std::flush;
653 TString t = TString::Format("%s %s", o.GetName(), o.ClassName());
654 const Int_t maxN = 75;
655 std::cout << "--- " << t << " " << std::setfill('-')
656 << std::setw(maxN-ind-5-t.Length()) << "-" << std::endl;
658 //____________________________________________________________________
660 AliForwardUtil::PrintName(const char* name)
662 Int_t ind = gROOT->GetDirLevel();
665 std::cout << std::setfill(' ') << std::setw(ind) << " " << std::flush;
667 // Now print field name
668 const Int_t maxN = 29;
669 Int_t width = maxN - ind;
671 if (n.Length() > width-1) {
672 // Truncate the string, and put in "..."
677 std::cout << std::setfill(' ') << std::left << std::setw(width)
678 << n << std::right << std::flush;
680 //____________________________________________________________________
682 AliForwardUtil::PrintField(const char* name, const char* value, ...)
686 // Now format the field value
689 static char buf[512];
690 vsnprintf(buf, 511, value, ap);
694 std::cout << buf << std::endl;
697 //====================================================================
698 #if 0 // Moved to separate classes
699 Int_t AliForwardUtil::fgConvolutionSteps = 100;
700 Double_t AliForwardUtil::fgConvolutionNSigma = 5;
703 // The shift of the most probable value for the ROOT function TMath::Landau
705 const Double_t mpshift = -0.22278298;
707 // Integration normalisation
709 const Double_t invSq2pi = 1. / TMath::Sqrt(2*TMath::Pi());
712 // Utility function to use in TF1 defintition
714 Double_t landauGaus1(Double_t* xp, Double_t* pp)
717 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
718 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
719 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
720 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
721 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
723 return constant * AliForwardUtil::LandauGaus(x, delta, xi, sigma, sigmaN);
726 Double_t landauGausComposite(Double_t* xp, Double_t* pp)
729 Double_t cP = pp[AliForwardUtil::ELossFitter::kC];
730 Double_t deltaP = pp[AliForwardUtil::ELossFitter::kDelta];
731 Double_t xiP = pp[AliForwardUtil::ELossFitter::kXi];
732 Double_t sigmaP = pp[AliForwardUtil::ELossFitter::kSigma];
733 Double_t cS = pp[AliForwardUtil::ELossFitter::kSigma+1];
734 Double_t deltaS = deltaP; // pp[AliForwardUtil::ELossFitter::kSigma+2];
735 Double_t xiS = pp[AliForwardUtil::ELossFitter::kSigma+2/*3*/];
736 Double_t sigmaS = sigmaP; // pp[AliForwardUtil::ELossFitter::kSigma+4];
738 return (cP * AliForwardUtil::LandauGaus(x,deltaP,xiP,sigmaP,0) +
739 cS * AliForwardUtil::LandauGaus(x,deltaS,xiS,sigmaS,0));
743 // Utility function to use in TF1 defintition
745 Double_t landauGausN(Double_t* xp, Double_t* pp)
748 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
749 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
750 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
751 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
752 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
753 Int_t n = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
754 Double_t* a = &(pp[AliForwardUtil::ELossFitter::kA]);
756 return constant * AliForwardUtil::NLandauGaus(x, delta, xi, sigma, sigmaN,
760 // Utility function to use in TF1 defintition
762 Double_t landauGausI(Double_t* xp, Double_t* pp)
765 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
766 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
767 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
768 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
769 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
770 Int_t i = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
772 return constant * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
777 //____________________________________________________________________
779 AliForwardUtil::Landau(Double_t x, Double_t delta, Double_t xi)
782 // Calculate the shifted Landau
784 // f'_{L}(x;\Delta,\xi) = f_L(x;\Delta+0.22278298\xi)
787 // where @f$ f_{L}@f$ is the ROOT implementation of the Landau
788 // distribution (known to have @f$ \Delta_{p}=-0.22278298@f$ for
789 // @f$\Delta=0,\xi=1@f$.
792 // x Where to evaluate @f$ f'_{L}@f$
793 // delta Most probable value
794 // xi The 'width' of the distribution
797 // @f$ f'_{L}(x;\Delta,\xi) @f$
799 Double_t deltaP = delta - xi * mpshift;
800 return TMath::Landau(x, deltaP, xi, true);
802 //____________________________________________________________________
804 AliForwardUtil::LandauGaus(Double_t x, Double_t delta, Double_t xi,
805 Double_t sigma, Double_t sigmaN)
808 // Calculate the value of a Landau convolved with a Gaussian
811 // f(x;\Delta,\xi,\sigma') = \frac{1}{\sigma' \sqrt{2 \pi}}
812 // \int_{-\infty}^{+\infty} d\Delta' f'_{L}(x;\Delta',\xi)
813 // \exp{-\frac{(\Delta-\Delta')^2}{2\sigma'^2}}
816 // where @f$ f'_{L}@f$ is the Landau distribution, @f$ \Delta@f$ the
817 // energy loss, @f$ \xi@f$ the width of the Landau, and
818 // @f$ \sigma'^2=\sigma^2-\sigma_n^2 @f$. Here, @f$\sigma@f$ is the
819 // variance of the Gaussian, and @f$\sigma_n@f$ is a parameter modelling
820 // noise in the detector.
822 // Note that this function uses the constants fgConvolutionSteps and
823 // fgConvolutionNSigma
826 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
827 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
828 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
831 // x where to evaluate @f$ f@f$
832 // delta @f$ \Delta@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
833 // xi @f$ \xi@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
834 // sigma @f$ \sigma@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
835 // sigma_n @f$ \sigma_n@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
838 // @f$ f@f$ evaluated at @f$ x@f$.
840 if (xi <= 0) return 0;
842 Double_t deltaP = delta; // - sigma * sigmaShift; // + sigma * mpshift;
843 Double_t sigma2 = sigmaN*sigmaN + sigma*sigma;
844 Double_t sigma1 = sigmaN == 0 ? sigma : TMath::Sqrt(sigma2);
845 Double_t xlow = x - fgConvolutionNSigma * sigma1;
846 Double_t xhigh = x + fgConvolutionNSigma * sigma1;
847 Double_t step = (xhigh - xlow) / fgConvolutionSteps;
850 for (Int_t i = 0; i <= fgConvolutionSteps/2; i++) {
851 Double_t x1 = xlow + (i - .5) * step;
852 Double_t x2 = xhigh - (i - .5) * step;
854 //sum += TMath::Landau(x1, deltap, xi, kTRUE) * TMath::Gaus(x, x1, sigma1);
855 //sum += TMath::Landau(x2, deltap, xi, kTRUE) * TMath::Gaus(x, x2, sigma1);
856 sum += Landau(x1, deltaP, xi) * TMath::Gaus(x, x1, sigma1);
857 sum += Landau(x2, deltaP, xi) * TMath::Gaus(x, x2, sigma1);
859 return step * sum * invSq2pi / sigma1;
863 const Double_t sigmaShift = 0.36390; // TMath::Log(TMath::Sqrt(2.));
864 double deltaSigmaShift(Int_t i, Double_t sigma)
866 return 0; // - sigma * sigmaShift;
868 void getIPars(Int_t i, Double_t& delta, Double_t& xi, Double_t& sigma)
870 Double_t dsig = deltaSigmaShift(i, sigma);
873 return; // { delta = delta + xi*mpshift; return; } // Do nothing
876 delta = i * (delta + xi * TMath::Log(i)) + dsig;
878 sigma = TMath::Sqrt(Double_t(i)) * sigma;
883 //____________________________________________________________________
885 AliForwardUtil::ILandauGaus(Double_t x, Double_t delta, Double_t xi,
886 Double_t sigma, Double_t sigmaN, Int_t i)
891 // f_i(x;\Delta,\xi,\sigma') = f(x;\Delta_i,\xi_i,\sigma_i')
893 // corresponding to @f$ i@f$ particles i.e., with the substitutions
895 // \Delta \rightarrow \Delta_i &=& i(\Delta + \xi\log(i))
896 // \xi \rightarrow \xi_i &=& i \xi
897 // \sigma \rightarrow \sigma_i &=& \sqrt{i}\sigma
898 // \sigma'^2 \rightarrow \sigma_i'^2 &=& \sigma_n^2 + \sigma_i^2
902 // x Where to evaluate
903 // delta @f$ \Delta@f$
905 // sigma @f$ \sigma@f$
906 // sigma_n @f$ \sigma_n@f$
910 // @f$ f_i @f$ evaluated
912 Double_t deltaI = delta;
914 Double_t sigmaI = sigma;
915 getIPars(i, deltaI, xiI, sigmaI);
916 if (sigmaI < 1e-10) {
917 // Fall back to landau
918 return AliForwardUtil::Landau(x, deltaI, xiI);
920 return AliForwardUtil::LandauGaus(x, deltaI, xiI, sigmaI, sigmaN);
923 //____________________________________________________________________
925 AliForwardUtil::IdLandauGausdPar(Double_t x,
926 UShort_t par, Double_t dPar,
927 Double_t delta, Double_t xi,
928 Double_t sigma, Double_t sigmaN,
932 // Numerically evaluate
934 // \left.\frac{\partial f_i}{\partial p_i}\right|_{x}
936 // where @f$ p_i@f$ is the @f$ i^{\mbox{th}}@f$ parameter. The mapping
937 // of the parameters is given by
942 // - 3: @f$\sigma_n@f$
944 // This is the partial derivative with respect to the parameter of
945 // the response function corresponding to @f$ i@f$ particles i.e.,
946 // with the substitutions
948 // \Delta \rightarrow \Delta_i = i(\Delta + \xi\log(i))
949 // \xi \rightarrow \xi_i = i \xi
950 // \sigma \rightarrow \sigma_i = \sqrt{i}\sigma
951 // \sigma'^2 \rightarrow \sigma_i'^2 = \sigma_n^2 + \sigma_i^2
955 // x Where to evaluate
956 // ipar Parameter number
957 // dp @f$ \epsilon\delta p_i@f$ for some value of @f$\epsilon@f$
958 // delta @f$ \Delta@f$
960 // sigma @f$ \sigma@f$
961 // sigma_n @f$ \sigma_n@f$
965 // @f$ f_i@f$ evaluated
967 if (dPar == 0) return 0;
969 Double_t d2 = dPar / 2;
970 Double_t deltaI = i * (delta + xi * TMath::Log(i));
971 Double_t xiI = i * xi;
972 Double_t si = TMath::Sqrt(Double_t(i));
973 Double_t sigmaI = si*sigma;
980 y1 = ILandauGaus(x, deltaI+i*dp, xiI, sigmaI, sigmaN, i);
981 y2 = ILandauGaus(x, deltaI+i*d2, xiI, sigmaI, sigmaN, i);
982 y3 = ILandauGaus(x, deltaI-i*d2, xiI, sigmaI, sigmaN, i);
983 y4 = ILandauGaus(x, deltaI-i*dp, xiI, sigmaI, sigmaN, i);
986 y1 = ILandauGaus(x, deltaI, xiI+i*dp, sigmaI, sigmaN, i);
987 y2 = ILandauGaus(x, deltaI, xiI+i*d2, sigmaI, sigmaN, i);
988 y3 = ILandauGaus(x, deltaI, xiI-i*d2, sigmaI, sigmaN, i);
989 y4 = ILandauGaus(x, deltaI, xiI-i*dp, sigmaI, sigmaN, i);
992 y1 = ILandauGaus(x, deltaI, xiI, sigmaI+si*dp, sigmaN, i);
993 y2 = ILandauGaus(x, deltaI, xiI, sigmaI+si*d2, sigmaN, i);
994 y3 = ILandauGaus(x, deltaI, xiI, sigmaI-si*d2, sigmaN, i);
995 y4 = ILandauGaus(x, deltaI, xiI, sigmaI-si*dp, sigmaN, i);
998 y1 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+dp, i);
999 y2 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+d2, i);
1000 y3 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-d2, i);
1001 y4 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-dp, i);
1007 Double_t d0 = y1 - y4;
1008 Double_t d1 = 2 * (y2 - y3);
1010 Double_t g = 1/(2*dp) * (4*d1 - d0) / 3;
1015 //____________________________________________________________________
1017 AliForwardUtil::NLandauGaus(Double_t x, Double_t delta, Double_t xi,
1018 Double_t sigma, Double_t sigmaN, Int_t n,
1024 // f_N(x;\Delta,\xi,\sigma') = \sum_{i=1}^N a_i f_i(x;\Delta,\xi,\sigma'a)
1027 // where @f$ f(x;\Delta,\xi,\sigma')@f$ is the convolution of a
1028 // Landau with a Gaussian (see LandauGaus). Note that
1029 // @f$ a_1 = 1@f$, @f$\Delta_i = i(\Delta_1 + \xi\log(i))@f$,
1030 // @f$\xi_i=i\xi_1@f$, and @f$\sigma_i'^2 = \sigma_n^2 + i\sigma_1^2@f$.
1033 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
1034 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
1035 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
1038 // x Where to evaluate @f$ f_N@f$
1039 // delta @f$ \Delta_1@f$
1041 // sigma @f$ \sigma_1@f$
1042 // sigma_n @f$ \sigma_n@f$
1043 // n @f$ N@f$ in the sum above.
1044 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
1048 // @f$ f_N(x;\Delta,\xi,\sigma')@f$
1050 Double_t result = ILandauGaus(x, delta, xi, sigma, sigmaN, 1);
1051 for (Int_t i = 2; i <= n; i++)
1052 result += a[i-2] * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
1056 const Int_t kColors[] = { kRed+1,
1070 //____________________________________________________________________
1072 AliForwardUtil::MakeNLandauGaus(Double_t c,
1073 Double_t delta, Double_t xi,
1074 Double_t sigma, Double_t sigmaN, Int_t n,
1076 Double_t xmin, Double_t xmax)
1079 // Generate a TF1 object of @f$ f_N@f$
1083 // delta @f$ \Delta@f$
1085 // sigma @f$ \sigma_1@f$
1086 // sigma_n @f$ \sigma_n@f$
1087 // n @f$ N@f$ - how many particles to sum to
1088 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
1090 // xmin Least value of range
1091 // xmax Largest value of range
1094 // Newly allocated TF1 object
1096 Int_t npar = AliForwardUtil::ELossFitter::kN+n;
1097 TF1* landaun = new TF1(Form("nlandau%d", n), &landauGausN,xmin,xmax,npar);
1098 // landaun->SetLineStyle(((n-2) % 10)+2); // start at dashed
1099 landaun->SetLineColor(kColors[((n-1) % 12)]); // start at red
1100 landaun->SetLineWidth(2);
1101 landaun->SetNpx(500);
1102 landaun->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "N");
1104 // Set the initial parameters from the seed fit
1105 landaun->SetParameter(AliForwardUtil::ELossFitter::kC, c);
1106 landaun->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
1107 landaun->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
1108 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
1109 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
1110 landaun->FixParameter(AliForwardUtil::ELossFitter::kN, n);
1112 // Set the range and name of the scale parameters
1113 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
1114 landaun->SetParameter(AliForwardUtil::ELossFitter::kA+i-2, a[i-2]);
1115 landaun->SetParName(AliForwardUtil::ELossFitter::kA+i-2, Form("a_{%d}", i));
1119 //____________________________________________________________________
1121 AliForwardUtil::MakeILandauGaus(Double_t c,
1122 Double_t delta, Double_t xi,
1123 Double_t sigma, Double_t sigmaN, Int_t i,
1124 Double_t xmin, Double_t xmax)
1127 // Generate a TF1 object of @f$ f_I@f$
1131 // delta @f$ \Delta@f$
1133 // sigma @f$ \sigma_1@f$
1134 // sigma_n @f$ \sigma_n@f$
1135 // i @f$ i@f$ - the number of particles
1136 // xmin Least value of range
1137 // xmax Largest value of range
1140 // Newly allocated TF1 object
1142 Int_t npar = AliForwardUtil::ELossFitter::kN+1;
1143 TF1* landaui = new TF1(Form("ilandau%d", i), &landauGausI,xmin,xmax,npar);
1144 // landaui->SetLineStyle(((i-2) % 10)+2); // start at dashed
1145 landaui->SetLineColor(kColors[((i-1) % 12)]); // start at red
1146 landaui->SetLineWidth(1);
1147 landaui->SetNpx(500);
1148 landaui->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "i");
1150 // Set the initial parameters from the seed fit
1151 landaui->SetParameter(AliForwardUtil::ELossFitter::kC, c);
1152 landaui->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
1153 landaui->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
1154 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
1155 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
1156 landaui->FixParameter(AliForwardUtil::ELossFitter::kN, i);
1161 //====================================================================
1162 AliForwardUtil::ELossFitter::ELossFitter(Double_t lowCut,
1165 : fLowCut(lowCut), fMaxRange(maxRange), fMinusBins(minusBins),
1166 fFitResults(0), fFunctions(0), fDebug(false)
1172 // lowCut Lower cut of spectrum - data below this cuts is ignored
1173 // maxRange Maximum range to fit to
1174 // minusBins The number of bins below maximum to use
1176 fFitResults.SetOwner();
1177 fFunctions.SetOwner();
1179 //____________________________________________________________________
1180 AliForwardUtil::ELossFitter::~ELossFitter()
1186 fFitResults.Delete();
1187 fFunctions.Delete();
1189 //____________________________________________________________________
1191 AliForwardUtil::ELossFitter::Clear()
1194 // Clear internal arrays
1197 fFitResults.Clear();
1201 void setParLimit(TF1* f, Int_t iPar, Bool_t debug,
1202 Double_t test, Double_t low, Double_t high)
1204 if (test >= low && test <= high) {
1206 printf("Fit: Set par limits on %s: %f, %f\n",
1207 f->GetParName(iPar), low, high);
1208 f->SetParLimits(iPar, low, high);
1213 //____________________________________________________________________
1215 AliForwardUtil::ELossFitter::Fit1Particle(TH1* dist, Double_t sigman)
1218 // Fit a 1-particle signal to the passed energy loss distribution
1220 // Note that this function clears the internal arrays first
1223 // dist Data to fit the function to
1224 // sigman If larger than zero, the initial guess of the
1225 // detector induced noise. If zero or less, then this
1226 // parameter is ignored in the fit (fixed at 0)
1229 // The function fitted to the data
1235 // Find the fit range
1236 // Find the fit range
1237 Int_t cutBin = TMath::Max(dist->GetXaxis()->FindBin(fLowCut),3);
1238 Int_t maxBin = TMath::Min(dist->GetXaxis()->FindBin(fMaxRange),
1240 dist->GetXaxis()->SetRange(cutBin, maxBin);
1241 // dist->GetXaxis()->SetRangeUser(fLowCut, fMaxRange);
1243 // Get the bin with maximum
1244 Int_t peakBin = dist->GetMaximumBin();
1245 Double_t peakE = dist->GetBinLowEdge(peakBin);
1246 Double_t rmsE = dist->GetRMS();
1249 // dist->GetXaxis()->SetRangeUser(fLowCut, peakE);
1250 Int_t minBin = peakBin - fMinusBins; // dist->GetMinimumBin();
1251 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
1252 Double_t maxE = dist->GetBinCenter(peakBin+2*fMinusBins);
1254 Int_t minEb = dist->GetXaxis()->FindBin(minE);
1255 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
1256 Double_t intg = dist->Integral(minEb, maxEb);
1258 ::Warning("Fit1Particle",
1259 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
1260 dist->GetName(), minE, maxE, minEb, maxEb, intg);
1264 // Restore the range
1265 dist->GetXaxis()->SetRange(1, maxBin);
1267 // Define the function to fit
1268 TF1* landau1 = new TF1("landau1", landauGaus1, minE,maxE,kSigmaN+1);
1270 // Set initial guesses, parameter names, and limits
1271 landau1->SetParameters(intg,peakE,peakE/10,peakE/5,sigman);
1272 landau1->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
1273 landau1->SetNpx(500);
1274 setParLimit(landau1, kDelta, fDebug, peakE, minE, fMaxRange);
1275 setParLimit(landau1, kXi, fDebug, peakE, 0, rmsE); // 0.1
1276 setParLimit(landau1, kSigma, fDebug, peakE/5, 1e-5, rmsE); // 0.1
1277 if (sigman <= 0) landau1->FixParameter(kSigmaN, 0);
1279 setParLimit(landau1, kSigmaN, fDebug, peakE, 0, rmsE);
1282 TString opts(Form("%s%s", FIT_OPTIONS, fDebug ? "" : "Q"));
1283 // Do the fit, getting the result object
1285 ::Info("Fit1Particle", "Fitting in the range %f,%f", minE, maxE);
1286 TFitResultPtr r = dist->Fit(landau1, opts, "", minE, maxE);
1288 ::Warning("Fit1Particle",
1289 "No fit returned when processing %s in the range [%f,%f] "
1290 "options %s", dist->GetName(), minE, maxE, FIT_OPTIONS);
1293 // landau1->SetRange(minE, fMaxRange);
1294 fFitResults.AddAtAndExpand(new TFitResult(*r), 0);
1295 fFunctions.AddAtAndExpand(landau1, 0);
1299 //____________________________________________________________________
1301 AliForwardUtil::ELossFitter::FitNParticle(TH1* dist, UShort_t n,
1305 // Fit a N-particle signal to the passed energy loss distribution
1307 // If there's no 1-particle fit present, it does that first
1310 // dist Data to fit the function to
1311 // n Number of particle signals to fit
1312 // sigman If larger than zero, the initial guess of the
1313 // detector induced noise. If zero or less, then this
1314 // parameter is ignored in the fit (fixed at 0)
1317 // The function fitted to the data
1320 // Get the seed fit result
1321 TFitResult* r = static_cast<TFitResult*>(fFitResults.At(0));
1322 TF1* f = static_cast<TF1*>(fFunctions.At(0));
1324 f = Fit1Particle(dist, sigman);
1325 r = static_cast<TFitResult*>(fFitResults.At(0));
1327 ::Warning("FitNLandau", "No first shot at landau fit");
1332 // Get some parameters from seed fit
1333 Double_t delta1 = r->Parameter(kDelta);
1334 Double_t xi1 = r->Parameter(kXi);
1335 Double_t maxEi = n * (delta1 + xi1 * TMath::Log(n)) + 2 * n * xi1;
1336 Double_t minE = f->GetXmin();
1338 Int_t minEb = dist->GetXaxis()->FindBin(minE);
1339 Int_t maxEb = dist->GetXaxis()->FindBin(maxEi);
1340 Double_t rmsE = dist->GetRMS();
1341 Double_t intg = dist->Integral(minEb, maxEb);
1343 ::Warning("FitNParticle",
1344 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
1345 dist->GetName(), minE, maxEi, minEb, maxEb, intg);
1351 for (UShort_t i = 2; i <= n; i++)
1352 a.fArray[i-2] = (n == 2 ? 0.05 : 0.000001);
1353 // Make the fit function
1354 TF1* landaun = MakeNLandauGaus(r->Parameter(kC),
1355 r->Parameter(kDelta),
1357 r->Parameter(kSigma),
1358 r->Parameter(kSigmaN),
1359 n, a.fArray, minE, maxEi);
1360 setParLimit(landaun, kDelta, fDebug, r->Parameter(kDelta), minE, fMaxRange);
1361 setParLimit(landaun, kXi, fDebug, r->Parameter(kXi), 0, rmsE); // 0.1
1362 setParLimit(landaun, kSigma, fDebug, r->Parameter(kSigma), 1e-5, rmsE); // 0.1
1363 if (sigman <= 0) landaun->FixParameter(kSigmaN, 0);
1365 setParLimit(landaun, kSigmaN, fDebug, r->Parameter(kSigmaN), 0, rmsE);
1367 // Set the range and name of the scale parameters
1368 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
1369 setParLimit(landaun, kA+i-2, fDebug, a[i-2], 0, 1);
1373 TString opts(Form("%s%s", FIT_OPTIONS, fDebug ? "" : "Q"));
1375 ::Info("FitNParticle", "Fitting in the range %f,%f (%d)", minE, maxEi, n);
1376 TFitResultPtr tr = dist->Fit(landaun, opts, "", minE, maxEi);
1378 // landaun->SetRange(minE, fMaxRange);
1379 fFitResults.AddAtAndExpand(new TFitResult(*tr), n-1);
1380 fFunctions.AddAtAndExpand(landaun, n-1);
1384 //____________________________________________________________________
1386 AliForwardUtil::ELossFitter::FitComposite(TH1* dist, Double_t sigman)
1389 // Fit a composite particle signal to the passed energy loss
1392 // dist Data to fit the function to
1393 // sigman If larger than zero, the initial guess of the
1394 // detector induced noise. If zero or less, then this
1395 // parameter is ignored in the fit (fixed at 0)
1398 // The function fitted to the data
1401 // Find the fit range
1402 Int_t cutBin = TMath::Max(dist->GetXaxis()->FindBin(fLowCut),3);
1403 Int_t maxBin = TMath::Min(dist->GetXaxis()->FindBin(fMaxRange),
1405 dist->GetXaxis()->SetRange(cutBin, maxBin);
1407 // Get the bin with maximum
1408 Int_t peakBin = dist->GetMaximumBin();
1409 Double_t peakE = dist->GetBinLowEdge(peakBin);
1412 // dist->GetXaxis()->SetRangeUser(fLowCut, peakE);
1413 Int_t minBin = peakBin - fMinusBins; // dist->GetMinimumBin();
1414 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
1415 Double_t maxE = dist->GetBinCenter(peakBin+2*fMinusBins);
1417 // Get the range in bins and the integral of that range
1418 Int_t minEb = dist->GetXaxis()->FindBin(minE);
1419 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
1420 Double_t intg = dist->Integral(minEb, maxEb);
1422 ::Warning("Fit1Particle",
1423 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
1424 dist->GetName(), minE, maxE, minEb, maxEb, intg);
1428 // Restore the range
1429 dist->GetXaxis()->SetRange(1, maxBin);
1431 // Define the function to fit
1432 TF1* seed = new TF1("landauSeed", landauGaus1, minE,maxE,kSigmaN+1);
1434 // Set initial guesses, parameter names, and limits
1435 seed->SetParameters(1,peakE,peakE/10,peakE/5,sigman);
1436 seed->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
1438 seed->SetParLimits(kDelta, minE, fMaxRange);
1439 seed->SetParLimits(kXi, 0.00, 0.1); // Was fMaxRange - too wide
1440 seed->SetParLimits(kSigma, 1e-5, 0.1); // Was fMaxRange - too wide
1441 if (sigman <= 0) seed->FixParameter(kSigmaN, 0);
1442 else seed->SetParLimits(kSigmaN, 0, fMaxRange);
1444 // Do the fit, getting the result object
1446 ::Info("FitComposite", "Fitting seed in the range %f,%f", minE, maxE);
1447 /* TFitResultPtr r = */ dist->Fit(seed, FIT_OPTIONS, "", minE, maxE);
1449 maxE = dist->GetXaxis()->GetXmax();
1451 TF1* comp = new TF1("composite", landauGausComposite,
1452 minE, maxE, kSigma+1+2);
1453 comp->SetParNames("C", "#Delta_{p}", "#xi", "#sigma",
1454 "C#prime", "#xi#prime");
1455 comp->SetParameters(0.8 * seed->GetParameter(kC), // 0 Primary weight
1456 seed->GetParameter(kDelta), // 1 Primary Delta
1457 seed->GetParameter(kDelta)/10, // 2 primary Xi
1458 seed->GetParameter(kDelta)/5, // 3 primary sigma
1459 1.20 * seed->GetParameter(kC), // 5 Secondary weight
1460 seed->GetParameter(kXi)); // 7 secondary Xi
1461 // comp->SetParLimits(kC, minE, fMaxRange); // C
1462 comp->SetParLimits(kDelta, minE, fMaxRange); // Delta
1463 comp->SetParLimits(kXi, 0.00, fMaxRange); // Xi
1464 comp->SetParLimits(kSigma, 1e-5, fMaxRange); // Sigma
1465 // comp->SetParLimits(kSigma+1, minE, fMaxRange); // C
1466 comp->SetParLimits(kSigma+2, 0.00, fMaxRange); // Xi'
1468 TF1* comp = new TF1("composite", landauGausComposite,
1469 minE, maxE, kSigma+1+4);
1470 comp->SetParNames("C", "#Delta_{p}", "#xi", "#sigma",
1471 "C#prime", "#Delta_{p}#prime", "#xi#prime", "#sigma#prim");
1472 comp->SetParameters(0.8 * seed->GetParameter(kC), // 0 Primary weight
1473 seed->GetParameter(kDelta), // 1 Primary Delta
1474 seed->GetParameter(kDelta)/10, // 2 primary Xi
1475 seed->GetParameter(kDelta)/5, // 3 primary sigma
1476 1.20 * seed->GetParameter(kC), // 5 Secondary weight
1477 seed->GetParameter(kDelta), // 6 secondary Delta
1478 seed->GetParameter(kXi), // 7 secondary Xi
1479 seed->GetParameter(kSigma)); // 8 secondary sigma
1480 // comp->SetParLimits(kC, minE, fMaxRange); // C
1481 comp->SetParLimits(kDelta, minE, fMaxRange); // Delta
1482 comp->SetParLimits(kXi, 0.00, fMaxRange); // Xi
1483 comp->SetParLimits(kSigma, 1e-5, fMaxRange); // Sigma
1484 // comp->SetParLimits(kSigma+1, minE, fMaxRange); // C
1485 comp->SetParLimits(kSigma+2, minE/10, fMaxRange); // Delta
1486 comp->SetParLimits(kSigma+3, 0.00, fMaxRange); // Xi
1487 comp->SetParLimits(kSigma+4, 1e-6, fMaxRange); // Sigma
1489 comp->SetLineColor(kRed+1);
1490 comp->SetLineWidth(3);
1492 // Do the fit, getting the result object
1493 TString opts(Form("%s%s", FIT_OPTIONS, fDebug ? "" : "Q"));
1495 ::Info("FitComposite", "Fitting composite in the range %f,%f", minE, maxE);
1496 /* TFitResultPtr r = */ dist->Fit(comp, opts, "", minE, maxE);
1499 TF1* part1 = static_cast<TF1*>(seed->Clone("part1"));
1500 part1->SetLineColor(kGreen+1);
1501 part1->SetLineWidth(4);
1502 part1->SetRange(minE, maxE);
1503 part1->SetParameters(comp->GetParameter(0), // C
1504 comp->GetParameter(1), // Delta
1505 comp->GetParameter(2), // Xi
1506 comp->GetParameter(3), // sigma
1508 part1->Save(minE,maxE,0,0,0,0);
1509 dist->GetListOfFunctions()->Add(part1);
1511 TF1* part2 = static_cast<TF1*>(seed->Clone("part2"));
1512 part2->SetLineColor(kBlue+1);
1513 part2->SetLineWidth(4);
1514 part2->SetRange(minE, maxE);
1515 part2->SetParameters(comp->GetParameter(4), // C
1516 comp->GetParameter(5), // Delta
1517 comp->GetParameter(6), // Xi
1518 comp->GetParameter(7), // sigma
1520 part2->Save(minE,maxE,0,0,0,0);
1521 dist->GetListOfFunctions()->Add(part2);
1527 //====================================================================
1528 AliForwardUtil::Histos::~Histos()
1535 //____________________________________________________________________
1537 AliForwardUtil::Histos::Delete(Option_t* opt)
1539 if (fFMD1i) delete fFMD1i;
1540 if (fFMD2i) delete fFMD2i;
1541 if (fFMD2o) delete fFMD2o;
1542 if (fFMD3i) delete fFMD3i;
1543 if (fFMD3o) delete fFMD3o;
1549 TObject::Delete(opt);
1552 //____________________________________________________________________
1554 AliForwardUtil::Histos::Make(UShort_t d, Char_t r, const TAxis& etaAxis)
1562 // etaAxis Eta axis to use
1565 // Newly allocated histogram
1567 Int_t ns = (r == 'I' || r == 'i') ? 20 : 40;
1569 if (etaAxis.GetXbins() && etaAxis.GetXbins()->GetArray())
1570 hist = new TH2D(Form("FMD%d%c_cache", d, r),
1571 Form("FMD%d%c cache", d, r),
1572 etaAxis.GetNbins(), etaAxis.GetXbins()->GetArray(),
1573 ns, 0, TMath::TwoPi());
1575 hist = new TH2D(Form("FMD%d%c_cache", d, r),
1576 Form("FMD%d%c cache", d, r),
1577 etaAxis.GetNbins(), etaAxis.GetXmin(),
1578 etaAxis.GetXmax(), ns, 0, TMath::TwoPi());
1579 hist->SetXTitle("#eta");
1580 hist->SetYTitle("#phi [radians]");
1581 hist->SetZTitle("d^{2}N_{ch}/d#etad#phi");
1583 hist->SetDirectory(0);
1587 //____________________________________________________________________
1589 AliForwardUtil::Histos::RebinEta(TH2D* hist, const TAxis& etaAxis)
1591 TAxis* xAxis = hist->GetXaxis();
1592 if (etaAxis.GetXbins() && etaAxis.GetXbins()->GetArray())
1593 xAxis->Set(etaAxis.GetNbins(), etaAxis.GetXbins()->GetArray());
1595 xAxis->Set(etaAxis.GetNbins(), etaAxis.GetXmin(), etaAxis.GetXmax());
1600 //____________________________________________________________________
1602 AliForwardUtil::Histos::Init(const TAxis& etaAxis)
1605 // Initialize the object
1608 // etaAxis Eta axis to use
1610 fFMD1i = Make(1, 'I', etaAxis);
1611 fFMD2i = Make(2, 'I', etaAxis);
1612 fFMD2o = Make(2, 'O', etaAxis);
1613 fFMD3i = Make(3, 'I', etaAxis);
1614 fFMD3o = Make(3, 'O', etaAxis);
1616 //____________________________________________________________________
1618 AliForwardUtil::Histos::ReInit(const TAxis& etaAxis)
1621 // Initialize the object
1624 // etaAxis Eta axis to use
1626 if (!fFMD1i) fFMD1i = Make(1, 'i', etaAxis); else RebinEta(fFMD1i, etaAxis);
1627 if (!fFMD2i) fFMD2i = Make(2, 'i', etaAxis); else RebinEta(fFMD2i, etaAxis);
1628 if (!fFMD2o) fFMD2o = Make(2, 'o', etaAxis); else RebinEta(fFMD2o, etaAxis);
1629 if (!fFMD3i) fFMD3i = Make(3, 'i', etaAxis); else RebinEta(fFMD3i, etaAxis);
1630 if (!fFMD3o) fFMD3o = Make(3, 'o', etaAxis); else RebinEta(fFMD3o, etaAxis);
1633 //____________________________________________________________________
1635 AliForwardUtil::Histos::Clear(Option_t* option)
1643 if (fFMD1i) { fFMD1i->Reset(option); fFMD1i->ResetBit(kSkipRing); }
1644 if (fFMD2i) { fFMD2i->Reset(option); fFMD2i->ResetBit(kSkipRing); }
1645 if (fFMD2o) { fFMD2o->Reset(option); fFMD2o->ResetBit(kSkipRing); }
1646 if (fFMD3i) { fFMD3i->Reset(option); fFMD3i->ResetBit(kSkipRing); }
1647 if (fFMD3o) { fFMD3o->Reset(option); fFMD3o->ResetBit(kSkipRing); }
1650 //____________________________________________________________________
1652 AliForwardUtil::Histos::Get(UShort_t d, Char_t r) const
1655 // Get the histogram for a particular detector,ring
1662 // Histogram for detector,ring or nul
1665 case 1: return fFMD1i;
1666 case 2: return (r == 'I' || r == 'i' ? fFMD2i : fFMD2o);
1667 case 3: return (r == 'I' || r == 'i' ? fFMD3i : fFMD3o);
1671 //====================================================================
1673 AliForwardUtil::RingHistos::DefineOutputList(TList* d) const
1676 // Define the outout list in @a d
1679 // d Where to put the output list
1682 // Newly allocated TList object or null
1685 TList* list = new TList;
1687 list->SetName(fName.Data());
1691 //____________________________________________________________________
1693 AliForwardUtil::RingHistos::GetOutputList(const TList* d) const
1696 // Get our output list from the container @a d
1699 // d where to get the output list from
1702 // The found TList or null
1705 TList* list = static_cast<TList*>(d->FindObject(fName.Data()));
1709 //____________________________________________________________________
1711 AliForwardUtil::RingHistos::GetOutputHist(const TList* d, const char* name) const
1714 // Find a specific histogram in the source list @a d
1717 // d (top)-container
1718 // name Name of histogram
1721 // Found histogram or null
1723 return static_cast<TH1*>(d->FindObject(name));
1726 //====================================================================
1727 AliForwardUtil::DebugGuard::DebugGuard(Int_t lvl, Int_t msgLvl,
1728 const char* format, ...)
1731 if (lvl < msgLvl) return;
1733 va_start(ap, format);
1734 Format(fMsg, format, ap);
1738 //____________________________________________________________________
1739 AliForwardUtil::DebugGuard::~DebugGuard()
1741 if (fMsg.IsNull()) return;
1744 //____________________________________________________________________
1746 AliForwardUtil::DebugGuard::Message(Int_t lvl, Int_t msgLvl,
1747 const char* format, ...)
1749 if (lvl < msgLvl) return;
1752 va_start(ap, format);
1753 Format(msg, format, ap);
1758 //____________________________________________________________________
1760 AliForwardUtil::DebugGuard::Format(TString& out, const char* format, va_list ap)
1762 static char buf[512];
1763 Int_t n = gROOT->GetDirLevel() + 2;
1764 for (Int_t i = 0; i < n; i++) buf[i] = ' ';
1765 vsnprintf(&(buf[n]), 511-n, format, ap);
1769 //____________________________________________________________________
1771 AliForwardUtil::DebugGuard::Output(int in, TString& msg)
1773 msg[0] = (in > 0 ? '>' : in < 0 ? '<' : '=');
1774 AliLog::Message(AliLog::kInfo, msg, 0, 0, "PWGLF/forward", 0, 0);
1775 if (in > 0) gROOT->IncreaseDirLevel();
1776 else if (in < 0) gROOT->DecreaseDirLevel();