]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWGLF/FORWARD/analysis2/AliForwardUtil.cxx
A better way to specify the Nch axis for the MultDists task.
[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"
1ff25622 6//#include <ARVersion.h>
9d99b0dd 7#include <AliAnalysisManager.h>
8#include "AliAODForwardMult.h"
9#include <AliLog.h>
10#include <AliInputEventHandler.h>
290052e7 11#include <AliAODInputHandler.h>
12#include <AliAODHandler.h>
13#include <AliAODEvent.h>
9d99b0dd 14#include <AliESDEvent.h>
290052e7 15#include <AliAnalysisTaskSE.h>
9d99b0dd 16#include <AliPhysicsSelection.h>
17#include <AliTriggerAnalysis.h>
18#include <AliMultiplicity.h>
241cca4d 19#include <TParameter.h>
7e4038b5 20#include <TH2D.h>
9d99b0dd 21#include <TH1I.h>
7f759bb7 22#include <TF1.h>
23#include <TFitResult.h>
7e4038b5 24#include <TMath.h>
7f759bb7 25#include <TError.h>
f53fb4f6 26#include <TROOT.h>
e65b8b56 27#define FIT_OPTIONS "RNQS"
7f759bb7 28
1ff25622 29//====================================================================
30ULong_t AliForwardUtil::AliROOTRevision()
31{
32#ifdef ALIROOT_SVN_REVISION
33 return ALIROOT_SVN_REVISION;
34#else
35 return 0;
36#endif
37}
38//____________________________________________________________________
39ULong_t AliForwardUtil::AliROOTBranch()
40{
41#ifdef ALIROOT_SVN_BRANCH
42 static ULong_t ret = 0;
43 if (ret != 0) return ret;
44
45 TString str(ALIROOT_SVN_BRANCH);
46 if (str[0] == 'v') str.Remove(0,1);
47 if (str.EqualTo("trunk")) return ret = 0xFFFFFFFF;
48
49 TObjArray* tokens = str.Tokenize("-");
50 TObjString* pMajor = static_cast<TObjString*>(tokens->At(0));
51 TObjString* pMinor = static_cast<TObjString*>(tokens->At(1));
52 TObjString* pRelea = static_cast<TObjString*>(tokens->At(2));
53 TObjString* pAn = (tokens->GetEntries() > 3 ?
54 static_cast<TObjString*>(tokens->At(3)) : 0);
55 TString sMajor = pMajor->String().Strip(TString::kLeading, '0');
56 TString sMinor = pMinor->String().Strip(TString::kLeading, '0');
57 TString sRelea = pRelea->String().Strip(TString::kLeading, '0');
58
59 ret = (((sMajor.Atoi() & 0xFF) << 12) |
60 ((sMinor.Atoi() & 0xFF) << 8) |
61 ((sRelea.Atoi() & 0xFF) << 4) |
62 (pAn ? 0xAA : 0));
63
64 return ret;
65#else
66 return 0;
67#endif
68}
69
0bd4b00f 70//====================================================================
71UShort_t
72AliForwardUtil::ParseCollisionSystem(const char* sys)
73{
7984e5f7 74 //
75 // Parse a collision system spec given in a string. Known values are
76 //
0151a6c6 77 // - "ppb", "p-pb", "pa", "p-a" which returns kPPb
78 // - "pp", "p-p" which returns kPP
79 // - "PbPb", "Pb-Pb", "A-A", which returns kPbPb
7984e5f7 80 // - Everything else gives kUnknown
81 //
82 // Parameters:
83 // sys Collision system spec
84 //
85 // Return:
86 // Collision system id
87 //
0bd4b00f 88 TString s(sys);
89 s.ToLower();
0151a6c6 90 // we do pA first to avoid pp catch on ppb string (AH)
91 if (s.Contains("p-pb") || s.Contains("ppb")) return AliForwardUtil::kPPb;
92 if (s.Contains("p-a") || s.Contains("pa")) return AliForwardUtil::kPPb;
d4d486f8 93 if (s.Contains("a-p") || s.Contains("ap")) return AliForwardUtil::kPPb;
0151a6c6 94 if (s.Contains("p-p") || s.Contains("pp")) return AliForwardUtil::kPP;
95 if (s.Contains("pb-pb") || s.Contains("pbpb")) return AliForwardUtil::kPbPb;
96 if (s.Contains("a-a") || s.Contains("aa")) return AliForwardUtil::kPbPb;
0bd4b00f 97 return AliForwardUtil::kUnknown;
98}
99//____________________________________________________________________
100const char*
101AliForwardUtil::CollisionSystemString(UShort_t sys)
102{
7984e5f7 103 //
104 // Get a string representation of the collision system
105 //
106 // Parameters:
107 // sys Collision system
108 // - kPP -> "pp"
109 // - kPbPb -> "PbPb"
110 // - anything else gives "unknown"
111 //
112 // Return:
113 // String representation of the collision system
114 //
0bd4b00f 115 switch (sys) {
116 case AliForwardUtil::kPP: return "pp";
117 case AliForwardUtil::kPbPb: return "PbPb";
0151a6c6 118 case AliForwardUtil::kPPb: return "pPb";
0bd4b00f 119 }
120 return "unknown";
121}
38229ecd 122//____________________________________________________________________
123Float_t
124AliForwardUtil::BeamRapidity(Float_t beam, UShort_t z, UShort_t a)
125{
126 const Double_t pMass = 9.38271999999999995e-01;
127 const Double_t nMass = 9.39564999999999984e-01;
128 Double_t beamE = z * beam / 2;
129 Double_t beamM = z * pMass + (a - z) * nMass;
130 Double_t beamP = TMath::Sqrt(beamE * beamE - beamM * beamM);
131 Double_t beamY = .5* TMath::Log((beamE+beamP) / (beamE-beamP));
132 return beamY;
133}
134//____________________________________________________________________
135Float_t
136AliForwardUtil::CenterOfMassEnergy(Float_t beam,
137 UShort_t z1,
138 UShort_t a1,
139 Short_t z2,
140 Short_t a2)
141{
142 // Calculate the center of mass energy given target/projectile
143 // mass and charge numbers
144 if (z2 < 0) z2 = z1;
145 if (a2 < 0) a2 = a1;
146 return TMath::Sqrt(Float_t(z1*z2)/a1/a2) * beam;
147}
148//____________________________________________________________________
149Float_t
150AliForwardUtil::CenterOfMassRapidity(UShort_t z1,
151 UShort_t a1,
152 Short_t z2,
153 Short_t a2)
154{
155 // Calculate the center of mass rapidity (shift) given target/projectile
156 // mass and charge numbers
157 if (z2 < 0) z2 = z1;
158 if (a2 < 0) a2 = a1;
159 if (z2 == z1 && a2 == a1) return 0;
160 return .5 * TMath::Log(Float_t(z1*a2)/z2/a1);
161}
162
0bd4b00f 163//____________________________________________________________________
164UShort_t
38229ecd 165AliForwardUtil::ParseCenterOfMassEnergy(UShort_t sys, Float_t beam)
0bd4b00f 166{
7984e5f7 167 //
168 // Parse the center of mass energy given as a float and return known
169 // values as a unsigned integer
170 //
171 // Parameters:
38229ecd 172 // sys Collision system (needed for AA)
173 // beam Center of mass energy * total charge
7984e5f7 174 //
175 // Return:
176 // Center of mass energy per nucleon
177 //
38229ecd 178 Float_t energy = beam;
cc83fca2 179 // Below no longer needed apparently
180 // if (sys == AliForwardUtil::kPbPb) energy = energy / 208 * 82;
38229ecd 181 if (sys == AliForwardUtil::kPPb)
182 energy = CenterOfMassEnergy(beam, 82, 208, 1, 1);
8449e3e0 183 else if (sys == AliForwardUtil::kPbPb)
184 energy = CenterOfMassEnergy(beam, 82, 208, 82, 208);
0bd4b00f 185 if (TMath::Abs(energy - 900.) < 10) return 900;
186 if (TMath::Abs(energy - 2400.) < 10) return 2400;
8449e3e0 187 if (TMath::Abs(energy - 2760.) < 20) return 2760;
0151a6c6 188 if (TMath::Abs(energy - 4400.) < 10) return 4400;
38229ecd 189 if (TMath::Abs(energy - 5022.) < 10) return 5023;
0bd4b00f 190 if (TMath::Abs(energy - 5500.) < 40) return 5500;
191 if (TMath::Abs(energy - 7000.) < 10) return 7000;
4bcdcbc1 192 if (TMath::Abs(energy - 8000.) < 10) return 8000;
0bd4b00f 193 if (TMath::Abs(energy - 10000.) < 10) return 10000;
194 if (TMath::Abs(energy - 14000.) < 10) return 14000;
195 return 0;
196}
197//____________________________________________________________________
198const char*
199AliForwardUtil::CenterOfMassEnergyString(UShort_t cms)
200{
7984e5f7 201 //
202 // Get a string representation of the center of mass energy per nuclean
203 //
204 // Parameters:
205 // cms Center of mass energy per nucleon
206 //
207 // Return:
208 // String representation of the center of mass energy per nuclean
209 //
0bd4b00f 210 return Form("%04dGeV", cms);
211}
212//____________________________________________________________________
213Short_t
214AliForwardUtil::ParseMagneticField(Float_t v)
215{
7984e5f7 216 //
217 // Parse the magnetic field (in kG) as given by a floating point number
218 //
219 // Parameters:
220 // field Magnetic field in kG
221 //
222 // Return:
223 // Short integer value of magnetic field in kG
224 //
0bd4b00f 225 if (TMath::Abs(v - 5.) < 1 ) return +5;
226 if (TMath::Abs(v + 5.) < 1 ) return -5;
227 if (TMath::Abs(v) < 1) return 0;
228 return 999;
229}
230//____________________________________________________________________
231const char*
232AliForwardUtil::MagneticFieldString(Short_t f)
233{
7984e5f7 234 //
235 // Get a string representation of the magnetic field
236 //
237 // Parameters:
238 // field Magnetic field in kG
239 //
240 // Return:
241 // String representation of the magnetic field
242 //
0bd4b00f 243 return Form("%01dkG", f);
244}
290052e7 245//_____________________________________________________________________
246AliAODEvent* AliForwardUtil::GetAODEvent(AliAnalysisTaskSE* task)
247{
248 // Check if AOD is the output event
576472c1 249 if (!task) ::Fatal("GetAODEvent", "Null task given, cannot do that");
250
290052e7 251 AliAODEvent* ret = task->AODEvent();
252 if (ret) return ret;
253
254 // Check if AOD is the input event
255 ret = dynamic_cast<AliAODEvent*>(task->InputEvent());
256 if (!ret) ::Warning("GetAODEvent", "No AOD event found");
257
258 return ret;
259}
260//_____________________________________________________________________
261UShort_t AliForwardUtil::CheckForAOD()
262{
263 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
264 if (dynamic_cast<AliAODInputHandler*>(am->GetInputEventHandler())) {
265 ::Info("CheckForAOD", "Found AOD Input handler");
266 return 1;
267 }
268 if (dynamic_cast<AliAODHandler*>(am->GetOutputEventHandler())) {
269 ::Info("CheckForAOD", "Found AOD Output handler");
270 return 2;
271 }
272
273 ::Warning("CheckForAOD",
274 "Neither and input nor output AOD handler is specified");
275 return 0;
276}
277//_____________________________________________________________________
278Bool_t AliForwardUtil::CheckForTask(const char* clsOrName, Bool_t cls)
279{
280 AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
281 if (!cls) {
282 AliAnalysisTask* t = am->GetTask(clsOrName);
283 if (!t) {
284 ::Warning("CheckForTask", "Task %s not found in manager", clsOrName);
285 return false;
286 }
287 ::Info("CheckForTask", "Found task %s", clsOrName);
288 return true;
289 }
290 TClass* dep = gROOT->GetClass(clsOrName);
291 if (!dep) {
292 ::Warning("CheckForTask", "Unknown class %s for needed task", clsOrName);
293 return false;
294 }
295 TIter next(am->GetTasks());
296 TObject* o = 0;
297 while ((o = next())) {
298 if (o->IsA()->InheritsFrom(dep)) {
299 ::Info("CheckForTask", "Found task of class %s: %s",
300 clsOrName, o->GetName());
301 return true;
302 }
303 }
304 ::Warning("CheckForTask", "No task of class %s was found", clsOrName);
305 return false;
306}
307
241cca4d 308//_____________________________________________________________________
309TObject* AliForwardUtil::MakeParameter(const Char_t* name, UShort_t value)
310{
311 TParameter<int>* ret = new TParameter<int>(name, value);
8449e3e0 312 ret->SetMergeMode('f');
241cca4d 313 ret->SetUniqueID(value);
314 return ret;
315}
316//_____________________________________________________________________
317TObject* AliForwardUtil::MakeParameter(const Char_t* name, Int_t value)
318{
319 TParameter<int>* ret = new TParameter<int>(name, value);
8449e3e0 320 ret->SetMergeMode('f');
241cca4d 321 ret->SetUniqueID(value);
322 return ret;
323}
324//_____________________________________________________________________
1ff25622 325TObject* AliForwardUtil::MakeParameter(const Char_t* name, ULong_t value)
326{
327 TParameter<Long_t>* ret = new TParameter<Long_t>(name, value);
8449e3e0 328 ret->SetMergeMode('f');
1ff25622 329 ret->SetUniqueID(value);
330 return ret;
331}
332//_____________________________________________________________________
241cca4d 333TObject* AliForwardUtil::MakeParameter(const Char_t* name, Double_t value)
334{
335 TParameter<double>* ret = new TParameter<double>(name, value);
1f7aa5c7 336 // Float_t v = value;
337 // UInt_t* tmp = reinterpret_cast<UInt_t*>(&v);
8449e3e0 338 ret->SetMergeMode('f');
1f7aa5c7 339 // ret->SetUniqueID(*tmp);
241cca4d 340 return ret;
341}
342//_____________________________________________________________________
343TObject* AliForwardUtil::MakeParameter(const Char_t* name, Bool_t value)
344{
345 TParameter<bool>* ret = new TParameter<bool>(name, value);
8449e3e0 346 ret->SetMergeMode('f');
241cca4d 347 ret->SetUniqueID(value);
348 return ret;
349}
350
351//_____________________________________________________________________
352void AliForwardUtil::GetParameter(TObject* o, UShort_t& value)
353{
354 if (!o) return;
1f7aa5c7 355 TParameter<int>* p = static_cast<TParameter<int>*>(o);
e65b8b56 356 if (p->TestBit(BIT(19)))
1f7aa5c7 357 value = p->GetVal();
358 else
359 value = o->GetUniqueID();
241cca4d 360}
361//_____________________________________________________________________
362void AliForwardUtil::GetParameter(TObject* o, Int_t& value)
363{
364 if (!o) return;
1f7aa5c7 365 TParameter<int>* p = static_cast<TParameter<int>*>(o);
e65b8b56 366 if (p->TestBit(BIT(19)))
1f7aa5c7 367 value = p->GetVal();
368 else
369 value = o->GetUniqueID();
241cca4d 370}
371//_____________________________________________________________________
1ff25622 372void AliForwardUtil::GetParameter(TObject* o, ULong_t& value)
373{
374 if (!o) return;
1f7aa5c7 375 TParameter<Long_t>* p = static_cast<TParameter<Long_t>*>(o);
e65b8b56 376 if (p->TestBit(BIT(19)))
1f7aa5c7 377 value = p->GetVal();
378 else
379 value = o->GetUniqueID();
1ff25622 380}
381//_____________________________________________________________________
241cca4d 382void AliForwardUtil::GetParameter(TObject* o, Double_t& value)
383{
384 if (!o) return;
1f7aa5c7 385 TParameter<double>* p = static_cast<TParameter<double>*>(o);
e65b8b56 386 if (p->TestBit(BIT(19)))
1f7aa5c7 387 value = p->GetVal(); // o->GetUniqueID();
388 else {
389 UInt_t i = o->GetUniqueID();
390 Float_t v = *reinterpret_cast<Float_t*>(&i);
391 value = v;
392 }
241cca4d 393}
394//_____________________________________________________________________
395void AliForwardUtil::GetParameter(TObject* o, Bool_t& value)
396{
397 if (!o) return;
1f7aa5c7 398 TParameter<bool>* p = static_cast<TParameter<bool>*>(o);
e65b8b56 399 if (p->TestBit(BIT(19)))
1f7aa5c7 400 value = p->GetVal(); // o->GetUniqueID();
401 else
402 value = o->GetUniqueID();
241cca4d 403}
290052e7 404
1f7aa5c7 405#if 0
6f4a5c0d 406//_____________________________________________________________________
5ca83fee 407Double_t AliForwardUtil::GetStripR(Char_t ring, UShort_t strip)
6f4a5c0d 408{
1f7aa5c7 409 // Get max R of ring
410 //
411 // Optimized version that has a cache
412 static TArrayD inner;
413 static TArrayD outer;
414 if (inner.GetSize() <= 0 || outer.GetSize() <= 0) {
415 const Double_t minR[] = { 4.5213, 15.4 };
416 const Double_t maxR[] = { 17.2, 28.0 };
417 const Int_t nStr[] = { 512, 256 };
418 for (Int_t q = 0; q < 2; q++) {
419 TArrayD& a = (q == 0 ? inner : outer);
420 a.Set(nStr[q]);
421
422 for (Int_t it = 0; it < nStr[q]; it++) {
423 Double_t rad = maxR[q] - minR[q];
424 Double_t segment = rad / nStr[q];
425 Double_t r = minR[q] + segment*strip;
426 a[it] = r;
427 }
428 }
429 }
430 if (ring == 'I' || ring == 'i') return inner.At(strip);
431 return outer.At(strip);
432}
433#else
434//_____________________________________________________________________
435Double_t AliForwardUtil::GetStripR(Char_t ring, UShort_t strip)
436{
437 // Get max R of ring
438 //
439 // New implementation has only one branch
440 const Double_t minR[] = { 4.5213, 15.4 };
441 const Double_t maxR[] = { 17.2, 28.0 };
442 const Int_t nStr[] = { 512, 256 };
443
444 Int_t q = (ring == 'I' || ring == 'i') ? 0 : 1;
445 Double_t rad = maxR[q] - minR[q];
446 Double_t segment = rad / nStr[q];
447 Double_t r = minR[q] + segment*strip;
6f4a5c0d 448
5ca83fee 449 return r;
450}
1f7aa5c7 451#endif
5ca83fee 452
1f7aa5c7 453#if 1
454//_____________________________________________________________________
455Double_t AliForwardUtil::GetEtaFromStrip(UShort_t det, Char_t ring,
456 UShort_t sec, UShort_t strip,
457 Double_t zvtx)
458{
459 // Calculate eta from strip with vertex (redundant with
460 // AliESDFMD::Eta but support displaced vertices)
461 //
462 // Slightly more optimized version that uses less branching
463
464 // Get R of the strip
465 Double_t r = GetStripR(ring, strip);
466 Int_t hybrid = sec / 2;
467 Int_t q = (ring == 'I' || ring == 'i') ? 0 : 1;
468
469 const Double_t zs[][2] = { { 320.266, -999999 },
470 { 83.666, 74.966 },
471 { -63.066, -74.966 } };
472 if (det > 3 || zs[det-1][q] == -999999) return -999999;
473
474 Double_t z = zs[det-1][q];
475 if ((hybrid % 2) == 0) z -= .5;
476
477 Double_t theta = TMath::ATan2(r,z-zvtx);
478 Double_t eta = -1*TMath::Log(TMath::Tan(0.5*theta));
479
480 return eta;
481}
482#else
5ca83fee 483//_____________________________________________________________________
484Double_t AliForwardUtil::GetEtaFromStrip(UShort_t det, Char_t ring,
485 UShort_t sec, UShort_t strip,
486 Double_t zvtx)
487{
488 // Calculate eta from strip with vertex (redundant with
489 // AliESDFMD::Eta but support displaced vertices)
6f4a5c0d 490
5ca83fee 491 //Get max R of ring
492 Double_t r = GetStripR(ring, strip);
493 Int_t hybrid = sec / 2;
494 Bool_t inner = (ring == 'I' || ring == 'i');
495 Double_t z = 0;
1f7aa5c7 496
497
6f4a5c0d 498 switch (det) {
5ca83fee 499 case 1: z = 320.266; break;
500 case 2: z = (inner ? 83.666 : 74.966); break;
6f4a5c0d 501 case 3: z = (inner ? -63.066 : -74.966); break;
502 default: return -999999;
503 }
504 if ((hybrid % 2) == 0) z -= .5;
505
506 Double_t theta = TMath::ATan2(r,z-zvtx);
507 Double_t eta = -1*TMath::Log(TMath::Tan(0.5*theta));
508
509 return eta;
510}
1f7aa5c7 511#endif
0bd4b00f 512
5ca83fee 513//_____________________________________________________________________
514Double_t AliForwardUtil::GetPhiFromStrip(Char_t ring, UShort_t strip,
515 Double_t phi,
516 Double_t xvtx, Double_t yvtx)
517{
518 // Calculate eta from strip with vertex (redundant with
519 // AliESDFMD::Eta but support displaced vertices)
520
521 // Unknown x,y -> no change
522 if (yvtx > 999 || xvtx > 999) return phi;
523
524 //Get max R of ring
525 Double_t r = GetStripR(ring, strip);
526 Double_t amp = TMath::Sqrt(xvtx*xvtx+yvtx*yvtx) / r;
527 Double_t pha = (TMath::Abs(yvtx) < 1e-12 ? 0 : TMath::ATan2(xvtx, yvtx));
528 Double_t cha = amp * TMath::Cos(phi+pha);
529 phi += cha;
530 if (phi < 0) phi += TMath::TwoPi();
531 if (phi > TMath::TwoPi()) phi -= TMath::TwoPi();
532 return phi;
533}
0bd4b00f 534
7f759bb7 535//====================================================================
536Int_t AliForwardUtil::fgConvolutionSteps = 100;
537Double_t AliForwardUtil::fgConvolutionNSigma = 5;
538namespace {
7984e5f7 539 //
540 // The shift of the most probable value for the ROOT function TMath::Landau
541 //
7f759bb7 542 const Double_t mpshift = -0.22278298;
7984e5f7 543 //
544 // Integration normalisation
545 //
7f759bb7 546 const Double_t invSq2pi = 1. / TMath::Sqrt(2*TMath::Pi());
547
7984e5f7 548 //
549 // Utility function to use in TF1 defintition
550 //
7f759bb7 551 Double_t landauGaus1(Double_t* xp, Double_t* pp)
552 {
553 Double_t x = xp[0];
c389303e 554 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
555 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
556 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
557 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
1174780f 558 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
7f759bb7 559
1174780f 560 return constant * AliForwardUtil::LandauGaus(x, delta, xi, sigma, sigmaN);
7f759bb7 561 }
562
2e658fb9 563 Double_t landauGausComposite(Double_t* xp, Double_t* pp)
564 {
565 Double_t x = xp[0];
566 Double_t cP = pp[AliForwardUtil::ELossFitter::kC];
567 Double_t deltaP = pp[AliForwardUtil::ELossFitter::kDelta];
568 Double_t xiP = pp[AliForwardUtil::ELossFitter::kXi];
569 Double_t sigmaP = pp[AliForwardUtil::ELossFitter::kSigma];
570 Double_t cS = pp[AliForwardUtil::ELossFitter::kSigma+1];
571 Double_t deltaS = pp[AliForwardUtil::ELossFitter::kSigma+2];
572 Double_t xiS = pp[AliForwardUtil::ELossFitter::kSigma+3];
573 Double_t sigmaS = pp[AliForwardUtil::ELossFitter::kSigma+4];
574
575 return (cP * AliForwardUtil::LandauGaus(x,deltaP,xiP,sigmaP,0) +
576 cS * AliForwardUtil::LandauGaus(x,deltaS,xiS,sigmaS,0));
577 }
578
7984e5f7 579 //
580 // Utility function to use in TF1 defintition
581 //
7f759bb7 582 Double_t landauGausN(Double_t* xp, Double_t* pp)
583 {
584 Double_t x = xp[0];
c389303e 585 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
586 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
587 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
588 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
1174780f 589 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
c389303e 590 Int_t n = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
591 Double_t* a = &(pp[AliForwardUtil::ELossFitter::kA]);
7f759bb7 592
1174780f 593 return constant * AliForwardUtil::NLandauGaus(x, delta, xi, sigma, sigmaN,
7f759bb7 594 n, a);
595 }
7984e5f7 596 //
597 // Utility function to use in TF1 defintition
598 //
0bd4b00f 599 Double_t landauGausI(Double_t* xp, Double_t* pp)
600 {
601 Double_t x = xp[0];
602 Double_t constant = pp[AliForwardUtil::ELossFitter::kC];
603 Double_t delta = pp[AliForwardUtil::ELossFitter::kDelta];
604 Double_t xi = pp[AliForwardUtil::ELossFitter::kXi];
605 Double_t sigma = pp[AliForwardUtil::ELossFitter::kSigma];
1174780f 606 Double_t sigmaN = pp[AliForwardUtil::ELossFitter::kSigmaN];
0bd4b00f 607 Int_t i = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
608
1174780f 609 return constant * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
0bd4b00f 610 }
7f759bb7 611
612
613}
614//____________________________________________________________________
615Double_t
616AliForwardUtil::Landau(Double_t x, Double_t delta, Double_t xi)
617{
7984e5f7 618 //
619 // Calculate the shifted Landau
620 // @f[
621 // f'_{L}(x;\Delta,\xi) = f_L(x;\Delta+0.22278298\xi)
622 // @f]
623 //
624 // where @f$ f_{L}@f$ is the ROOT implementation of the Landau
625 // distribution (known to have @f$ \Delta_{p}=-0.22278298@f$ for
626 // @f$\Delta=0,\xi=1@f$.
627 //
628 // Parameters:
629 // x Where to evaluate @f$ f'_{L}@f$
630 // delta Most probable value
631 // xi The 'width' of the distribution
632 //
633 // Return:
634 // @f$ f'_{L}(x;\Delta,\xi) @f$
635 //
7f759bb7 636 return TMath::Landau(x, delta - xi * mpshift, xi);
637}
638//____________________________________________________________________
639Double_t
640AliForwardUtil::LandauGaus(Double_t x, Double_t delta, Double_t xi,
1174780f 641 Double_t sigma, Double_t sigmaN)
7f759bb7 642{
7984e5f7 643 //
644 // Calculate the value of a Landau convolved with a Gaussian
645 //
646 // @f[
647 // f(x;\Delta,\xi,\sigma') = \frac{1}{\sigma' \sqrt{2 \pi}}
648 // \int_{-\infty}^{+\infty} d\Delta' f'_{L}(x;\Delta',\xi)
649 // \exp{-\frac{(\Delta-\Delta')^2}{2\sigma'^2}}
650 // @f]
651 //
652 // where @f$ f'_{L}@f$ is the Landau distribution, @f$ \Delta@f$ the
653 // energy loss, @f$ \xi@f$ the width of the Landau, and
654 // @f$ \sigma'^2=\sigma^2-\sigma_n^2 @f$. Here, @f$\sigma@f$ is the
655 // variance of the Gaussian, and @f$\sigma_n@f$ is a parameter modelling
656 // noise in the detector.
657 //
658 // Note that this function uses the constants fgConvolutionSteps and
659 // fgConvolutionNSigma
660 //
661 // References:
662 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
663 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
664 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
665 //
666 // Parameters:
667 // x where to evaluate @f$ f@f$
668 // delta @f$ \Delta@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
669 // xi @f$ \xi@f$ of @f$ f(x;\Delta,\xi,\sigma')@f$
670 // sigma @f$ \sigma@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
671 // sigma_n @f$ \sigma_n@f$ of @f$\sigma'^2=\sigma^2-\sigma_n^2 @f$
672 //
673 // Return:
674 // @f$ f@f$ evaluated at @f$ x@f$.
675 //
7f759bb7 676 Double_t deltap = delta - xi * mpshift;
1174780f 677 Double_t sigma2 = sigmaN*sigmaN + sigma*sigma;
678 Double_t sigma1 = sigmaN == 0 ? sigma : TMath::Sqrt(sigma2);
7f759bb7 679 Double_t xlow = x - fgConvolutionNSigma * sigma1;
c389303e 680 Double_t xhigh = x + fgConvolutionNSigma * sigma1;
7f759bb7 681 Double_t step = (xhigh - xlow) / fgConvolutionSteps;
682 Double_t sum = 0;
683
684 for (Int_t i = 0; i <= fgConvolutionSteps/2; i++) {
c389303e 685 Double_t x1 = xlow + (i - .5) * step;
686 Double_t x2 = xhigh - (i - .5) * step;
7f759bb7 687
688 sum += TMath::Landau(x1, deltap, xi, kTRUE) * TMath::Gaus(x, x1, sigma1);
689 sum += TMath::Landau(x2, deltap, xi, kTRUE) * TMath::Gaus(x, x2, sigma1);
690 }
691 return step * sum * invSq2pi / sigma1;
692}
693
0bd4b00f 694//____________________________________________________________________
695Double_t
696AliForwardUtil::ILandauGaus(Double_t x, Double_t delta, Double_t xi,
1174780f 697 Double_t sigma, Double_t sigmaN, Int_t i)
0bd4b00f 698{
7984e5f7 699 //
700 // Evaluate
701 // @f[
702 // f_i(x;\Delta,\xi,\sigma') = f(x;\Delta_i,\xi_i,\sigma_i')
703 // @f]
704 // corresponding to @f$ i@f$ particles i.e., with the substitutions
705 // @f{eqnarray*}{
706 // \Delta \rightarrow \Delta_i &=& i(\Delta + \xi\log(i))
707 // \xi \rightarrow \xi_i &=& i \xi
708 // \sigma \rightarrow \sigma_i &=& \sqrt{i}\sigma
709 // \sigma'^2 \rightarrow \sigma_i'^2 &=& \sigma_n^2 + \sigma_i^2
710 // @f}
711 //
712 // Parameters:
713 // x Where to evaluate
714 // delta @f$ \Delta@f$
715 // xi @f$ \xi@f$
716 // sigma @f$ \sigma@f$
717 // sigma_n @f$ \sigma_n@f$
718 // i @f$ i @f$
719 //
720 // Return:
721 // @f$ f_i @f$ evaluated
722 //
1174780f 723 Double_t deltaI = (i == 1 ? delta : i * (delta + xi * TMath::Log(i)));
724 Double_t xiI = i * xi;
725 Double_t sigmaI = (i == 1 ? sigma : TMath::Sqrt(Double_t(i))*sigma);
726 if (sigmaI < 1e-10) {
0bd4b00f 727 // Fall back to landau
1174780f 728 return AliForwardUtil::Landau(x, deltaI, xiI);
0bd4b00f 729 }
1174780f 730 return AliForwardUtil::LandauGaus(x, deltaI, xiI, sigmaI, sigmaN);
0bd4b00f 731}
732
733//____________________________________________________________________
734Double_t
735AliForwardUtil::IdLandauGausdPar(Double_t x,
736 UShort_t par, Double_t dPar,
737 Double_t delta, Double_t xi,
1174780f 738 Double_t sigma, Double_t sigmaN,
0bd4b00f 739 Int_t i)
740{
7984e5f7 741 //
742 // Numerically evaluate
743 // @f[
744 // \left.\frac{\partial f_i}{\partial p_i}\right|_{x}
745 // @f]
746 // where @f$ p_i@f$ is the @f$ i^{\mbox{th}}@f$ parameter. The mapping
747 // of the parameters is given by
748 //
749 // - 0: @f$\Delta@f$
750 // - 1: @f$\xi@f$
751 // - 2: @f$\sigma@f$
752 // - 3: @f$\sigma_n@f$
753 //
754 // This is the partial derivative with respect to the parameter of
755 // the response function corresponding to @f$ i@f$ particles i.e.,
756 // with the substitutions
757 // @f[
758 // \Delta \rightarrow \Delta_i = i(\Delta + \xi\log(i))
759 // \xi \rightarrow \xi_i = i \xi
760 // \sigma \rightarrow \sigma_i = \sqrt{i}\sigma
761 // \sigma'^2 \rightarrow \sigma_i'^2 = \sigma_n^2 + \sigma_i^2
762 // @f]
763 //
764 // Parameters:
765 // x Where to evaluate
766 // ipar Parameter number
767 // dp @f$ \epsilon\delta p_i@f$ for some value of @f$\epsilon@f$
768 // delta @f$ \Delta@f$
769 // xi @f$ \xi@f$
770 // sigma @f$ \sigma@f$
771 // sigma_n @f$ \sigma_n@f$
772 // i @f$ i@f$
773 //
774 // Return:
775 // @f$ f_i@f$ evaluated
776 //
0bd4b00f 777 if (dPar == 0) return 0;
778 Double_t dp = dPar;
779 Double_t d2 = dPar / 2;
1174780f 780 Double_t deltaI = i * (delta + xi * TMath::Log(i));
781 Double_t xiI = i * xi;
0bd4b00f 782 Double_t si = TMath::Sqrt(Double_t(i));
1174780f 783 Double_t sigmaI = si*sigma;
0bd4b00f 784 Double_t y1 = 0;
785 Double_t y2 = 0;
786 Double_t y3 = 0;
787 Double_t y4 = 0;
788 switch (par) {
789 case 0:
1174780f 790 y1 = ILandauGaus(x, deltaI+i*dp, xiI, sigmaI, sigmaN, i);
791 y2 = ILandauGaus(x, deltaI+i*d2, xiI, sigmaI, sigmaN, i);
792 y3 = ILandauGaus(x, deltaI-i*d2, xiI, sigmaI, sigmaN, i);
793 y4 = ILandauGaus(x, deltaI-i*dp, xiI, sigmaI, sigmaN, i);
0bd4b00f 794 break;
795 case 1:
1174780f 796 y1 = ILandauGaus(x, deltaI, xiI+i*dp, sigmaI, sigmaN, i);
797 y2 = ILandauGaus(x, deltaI, xiI+i*d2, sigmaI, sigmaN, i);
798 y3 = ILandauGaus(x, deltaI, xiI-i*d2, sigmaI, sigmaN, i);
799 y4 = ILandauGaus(x, deltaI, xiI-i*dp, sigmaI, sigmaN, i);
0bd4b00f 800 break;
801 case 2:
1174780f 802 y1 = ILandauGaus(x, deltaI, xiI, sigmaI+si*dp, sigmaN, i);
803 y2 = ILandauGaus(x, deltaI, xiI, sigmaI+si*d2, sigmaN, i);
804 y3 = ILandauGaus(x, deltaI, xiI, sigmaI-si*d2, sigmaN, i);
805 y4 = ILandauGaus(x, deltaI, xiI, sigmaI-si*dp, sigmaN, i);
0bd4b00f 806 break;
807 case 3:
1174780f 808 y1 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+dp, i);
809 y2 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN+d2, i);
810 y3 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-d2, i);
811 y4 = ILandauGaus(x, deltaI, xiI, sigmaI, sigmaN-dp, i);
0bd4b00f 812 break;
813 default:
814 return 0;
815 }
816
817 Double_t d0 = y1 - y4;
818 Double_t d1 = 2 * (y2 - y3);
819
820 Double_t g = 1/(2*dp) * (4*d1 - d0) / 3;
821
822 return g;
823}
824
7f759bb7 825//____________________________________________________________________
826Double_t
827AliForwardUtil::NLandauGaus(Double_t x, Double_t delta, Double_t xi,
1174780f 828 Double_t sigma, Double_t sigmaN, Int_t n,
fb3430ac 829 const Double_t* a)
7f759bb7 830{
7984e5f7 831 //
832 // Evaluate
833 // @f[
834 // f_N(x;\Delta,\xi,\sigma') = \sum_{i=1}^N a_i f_i(x;\Delta,\xi,\sigma'a)
835 // @f]
836 //
837 // where @f$ f(x;\Delta,\xi,\sigma')@f$ is the convolution of a
838 // Landau with a Gaussian (see LandauGaus). Note that
839 // @f$ a_1 = 1@f$, @f$\Delta_i = i(\Delta_1 + \xi\log(i))@f$,
840 // @f$\xi_i=i\xi_1@f$, and @f$\sigma_i'^2 = \sigma_n^2 + i\sigma_1^2@f$.
841 //
842 // References:
843 // - <a href="http://dx.doi.org/10.1016/0168-583X(84)90472-5">Nucl.Instrum.Meth.B1:16</a>
844 // - <a href="http://dx.doi.org/10.1103/PhysRevA.28.615">Phys.Rev.A28:615</a>
845 // - <a href="http://root.cern.ch/root/htmldoc/tutorials/fit/langaus.C.html">ROOT implementation</a>
846 //
847 // Parameters:
848 // x Where to evaluate @f$ f_N@f$
849 // delta @f$ \Delta_1@f$
850 // xi @f$ \xi_1@f$
851 // sigma @f$ \sigma_1@f$
852 // sigma_n @f$ \sigma_n@f$
853 // n @f$ N@f$ in the sum above.
854 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
855 // @f$ i > 1@f$
856 //
857 // Return:
858 // @f$ f_N(x;\Delta,\xi,\sigma')@f$
859 //
1174780f 860 Double_t result = ILandauGaus(x, delta, xi, sigma, sigmaN, 1);
0bd4b00f 861 for (Int_t i = 2; i <= n; i++)
1174780f 862 result += a[i-2] * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigmaN,i);
7f759bb7 863 return result;
864}
0bd4b00f 865namespace {
866 const Int_t kColors[] = { kRed+1,
867 kPink+3,
868 kMagenta+2,
869 kViolet+2,
870 kBlue+1,
871 kAzure+3,
872 kCyan+1,
873 kTeal+2,
874 kGreen+2,
875 kSpring+3,
876 kYellow+2,
877 kOrange+2 };
878}
879
880//____________________________________________________________________
881TF1*
882AliForwardUtil::MakeNLandauGaus(Double_t c,
883 Double_t delta, Double_t xi,
1174780f 884 Double_t sigma, Double_t sigmaN, Int_t n,
fb3430ac 885 const Double_t* a,
0bd4b00f 886 Double_t xmin, Double_t xmax)
887{
7984e5f7 888 //
889 // Generate a TF1 object of @f$ f_N@f$
890 //
891 // Parameters:
892 // c Constant
893 // delta @f$ \Delta@f$
894 // xi @f$ \xi_1@f$
895 // sigma @f$ \sigma_1@f$
896 // sigma_n @f$ \sigma_n@f$
897 // n @f$ N@f$ - how many particles to sum to
898 // a Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for
899 // @f$ i > 1@f$
900 // xmin Least value of range
901 // xmax Largest value of range
902 //
903 // Return:
904 // Newly allocated TF1 object
905 //
0bd4b00f 906 Int_t npar = AliForwardUtil::ELossFitter::kN+n;
907 TF1* landaun = new TF1(Form("nlandau%d", n), &landauGausN,xmin,xmax,npar);
908 // landaun->SetLineStyle(((n-2) % 10)+2); // start at dashed
909 landaun->SetLineColor(kColors[((n-1) % 12)]); // start at red
910 landaun->SetLineWidth(2);
911 landaun->SetNpx(500);
912 landaun->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "N");
913
914 // Set the initial parameters from the seed fit
915 landaun->SetParameter(AliForwardUtil::ELossFitter::kC, c);
916 landaun->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
917 landaun->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
918 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
1174780f 919 landaun->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
0bd4b00f 920 landaun->FixParameter(AliForwardUtil::ELossFitter::kN, n);
921
922 // Set the range and name of the scale parameters
923 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
924 landaun->SetParameter(AliForwardUtil::ELossFitter::kA+i-2, a[i-2]);
925 landaun->SetParName(AliForwardUtil::ELossFitter::kA+i-2, Form("a_{%d}", i));
926 }
927 return landaun;
928}
929//____________________________________________________________________
930TF1*
931AliForwardUtil::MakeILandauGaus(Double_t c,
932 Double_t delta, Double_t xi,
1174780f 933 Double_t sigma, Double_t sigmaN, Int_t i,
0bd4b00f 934 Double_t xmin, Double_t xmax)
935{
7984e5f7 936 //
937 // Generate a TF1 object of @f$ f_I@f$
938 //
939 // Parameters:
940 // c Constant
941 // delta @f$ \Delta@f$
942 // xi @f$ \xi_1@f$
943 // sigma @f$ \sigma_1@f$
944 // sigma_n @f$ \sigma_n@f$
945 // i @f$ i@f$ - the number of particles
946 // xmin Least value of range
947 // xmax Largest value of range
948 //
949 // Return:
950 // Newly allocated TF1 object
951 //
0bd4b00f 952 Int_t npar = AliForwardUtil::ELossFitter::kN+1;
953 TF1* landaui = new TF1(Form("ilandau%d", i), &landauGausI,xmin,xmax,npar);
954 // landaui->SetLineStyle(((i-2) % 10)+2); // start at dashed
955 landaui->SetLineColor(kColors[((i-1) % 12)]); // start at red
956 landaui->SetLineWidth(1);
957 landaui->SetNpx(500);
958 landaui->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "i");
959
960 // Set the initial parameters from the seed fit
961 landaui->SetParameter(AliForwardUtil::ELossFitter::kC, c);
962 landaui->SetParameter(AliForwardUtil::ELossFitter::kDelta, delta);
963 landaui->SetParameter(AliForwardUtil::ELossFitter::kXi, xi);
964 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigma, sigma);
1174780f 965 landaui->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigmaN);
0bd4b00f 966 landaui->FixParameter(AliForwardUtil::ELossFitter::kN, i);
967
968 return landaui;
969}
7f759bb7 970
971//====================================================================
972AliForwardUtil::ELossFitter::ELossFitter(Double_t lowCut,
973 Double_t maxRange,
974 UShort_t minusBins)
975 : fLowCut(lowCut), fMaxRange(maxRange), fMinusBins(minusBins),
81775aba 976 fFitResults(0), fFunctions(0), fDebug(false)
7f759bb7 977{
7984e5f7 978 //
979 // Constructor
980 //
981 // Parameters:
982 // lowCut Lower cut of spectrum - data below this cuts is ignored
983 // maxRange Maximum range to fit to
984 // minusBins The number of bins below maximum to use
985 //
7f759bb7 986 fFitResults.SetOwner();
987 fFunctions.SetOwner();
988}
989//____________________________________________________________________
990AliForwardUtil::ELossFitter::~ELossFitter()
991{
7984e5f7 992 //
993 // Destructor
994 //
995 //
7f759bb7 996 fFitResults.Delete();
997 fFunctions.Delete();
998}
999//____________________________________________________________________
1000void
1001AliForwardUtil::ELossFitter::Clear()
1002{
7984e5f7 1003 //
1004 // Clear internal arrays
1005 //
1006 //
7f759bb7 1007 fFitResults.Clear();
1008 fFunctions.Clear();
1009}
1010//____________________________________________________________________
1011TF1*
1012AliForwardUtil::ELossFitter::Fit1Particle(TH1* dist, Double_t sigman)
1013{
7984e5f7 1014 //
1015 // Fit a 1-particle signal to the passed energy loss distribution
1016 //
1017 // Note that this function clears the internal arrays first
1018 //
1019 // Parameters:
1020 // dist Data to fit the function to
1021 // sigman If larger than zero, the initial guess of the
1022 // detector induced noise. If zero or less, then this
1023 // parameter is ignored in the fit (fixed at 0)
1024 //
1025 // Return:
1026 // The function fitted to the data
1027 //
1028
7f759bb7 1029 // Clear the cache
1030 Clear();
1031
1032 // Find the fit range
8449e3e0 1033 // Find the fit range
1034 Int_t cutBin = TMath::Max(dist->GetXaxis()->FindBin(fLowCut),3);
1035 Int_t maxBin = TMath::Min(dist->GetXaxis()->FindBin(fMaxRange),
1036 dist->GetNbinsX());
1037 dist->GetXaxis()->SetRange(cutBin, maxBin);
1038 // dist->GetXaxis()->SetRangeUser(fLowCut, fMaxRange);
7f759bb7 1039
7f759bb7 1040 // Get the bin with maximum
2e658fb9 1041 Int_t peakBin = dist->GetMaximumBin();
1042 Double_t peakE = dist->GetBinLowEdge(peakBin);
7f759bb7 1043
1044 // Get the low edge
8449e3e0 1045 // dist->GetXaxis()->SetRangeUser(fLowCut, peakE);
2e658fb9 1046 Int_t minBin = peakBin - fMinusBins; // dist->GetMinimumBin();
7f759bb7 1047 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
2e658fb9 1048 Double_t maxE = dist->GetBinCenter(peakBin+2*fMinusBins);
7f759bb7 1049
2e658fb9 1050 Int_t minEb = dist->GetXaxis()->FindBin(minE);
1051 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
1052 Double_t intg = dist->Integral(minEb, maxEb);
1053 if (intg <= 0) {
1054 ::Warning("Fit1Particle",
1055 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
1056 dist->GetName(), minE, maxE, minEb, maxEb, intg);
1057 return 0;
1058 }
1059
7f759bb7 1060 // Restore the range
8449e3e0 1061 dist->GetXaxis()->SetRange(1, maxBin);
7f759bb7 1062
1063 // Define the function to fit
2e658fb9 1064 TF1* landau1 = new TF1("landau1", landauGaus1, minE,maxE,kSigmaN+1);
7f759bb7 1065
1066 // Set initial guesses, parameter names, and limits
2e658fb9 1067 landau1->SetParameters(1,peakE,peakE/10,peakE/5,sigman);
7f759bb7 1068 landau1->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
c389303e 1069 landau1->SetNpx(500);
81775aba 1070 if (peakE >= minE && peakE <= fMaxRange) {
1071 // printf("Fit1: Set par limits on Delta: %f, %f\n", minE, fMaxRange);
1072 landau1->SetParLimits(kDelta, minE, fMaxRange);
1073 }
1074 if (peakE/10 >= 0 && peakE <= 0.1) {
1075 // printf("Fit1: Set par limits on xi: %f, %f\n", 0., 0.1);
1076 landau1->SetParLimits(kXi, 0.00, 0.1); // Was fMaxRange - too wide
1077 }
1078 if (peakE/5 >= 0 && peakE/5 <= 0.1) {
1079 // printf("Fit1: Set par limits on sigma: %f, %f\n", 0., 0.1);
1080 landau1->SetParLimits(kSigma, 1e-5, 0.1); // Was fMaxRange - too wide
1081 }
c389303e 1082 if (sigman <= 0) landau1->FixParameter(kSigmaN, 0);
81775aba 1083 else {
1084 // printf("Fit1: Set par limits on sigmaN: %f, %f\n", 0., fMaxRange);
1085 landau1->SetParLimits(kSigmaN, 0, fMaxRange);
1086 }
7f759bb7 1087
1088 // Do the fit, getting the result object
81775aba 1089 if (fDebug)
1090 ::Info("Fit1Particle", "Fitting in the range %f,%f", minE, maxE);
e65b8b56 1091 TFitResultPtr r = dist->Fit(landau1, FIT_OPTIONS, "", minE, maxE);
2e658fb9 1092 // landau1->SetRange(minE, fMaxRange);
7f759bb7 1093 fFitResults.AddAtAndExpand(new TFitResult(*r), 0);
1094 fFunctions.AddAtAndExpand(landau1, 0);
1095
1096 return landau1;
1097}
1098//____________________________________________________________________
1099TF1*
1100AliForwardUtil::ELossFitter::FitNParticle(TH1* dist, UShort_t n,
1101 Double_t sigman)
1102{
7984e5f7 1103 //
1104 // Fit a N-particle signal to the passed energy loss distribution
1105 //
1106 // If there's no 1-particle fit present, it does that first
1107 //
1108 // Parameters:
1109 // dist Data to fit the function to
1110 // n Number of particle signals to fit
1111 // sigman If larger than zero, the initial guess of the
1112 // detector induced noise. If zero or less, then this
1113 // parameter is ignored in the fit (fixed at 0)
1114 //
1115 // Return:
1116 // The function fitted to the data
1117 //
1118
7f759bb7 1119 // Get the seed fit result
1120 TFitResult* r = static_cast<TFitResult*>(fFitResults.At(0));
1121 TF1* f = static_cast<TF1*>(fFunctions.At(0));
1122 if (!r || !f) {
1123 f = Fit1Particle(dist, sigman);
1124 r = static_cast<TFitResult*>(fFitResults.At(0));
1125 if (!r || !f) {
1126 ::Warning("FitNLandau", "No first shot at landau fit");
1127 return 0;
1128 }
1129 }
1130
1131 // Get some parameters from seed fit
c389303e 1132 Double_t delta1 = r->Parameter(kDelta);
1133 Double_t xi1 = r->Parameter(kXi);
7f759bb7 1134 Double_t maxEi = n * (delta1 + xi1 * TMath::Log(n)) + 2 * n * xi1;
1135 Double_t minE = f->GetXmin();
1136
2e658fb9 1137 Int_t minEb = dist->GetXaxis()->FindBin(minE);
1138 Int_t maxEb = dist->GetXaxis()->FindBin(maxEi);
1139 Double_t intg = dist->Integral(minEb, maxEb);
1140 if (intg <= 0) {
1141 ::Warning("FitNParticle",
1142 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
1143 dist->GetName(), minE, maxEi, minEb, maxEb, intg);
1144 return 0;
1145 }
1146
0bd4b00f 1147 // Array of weights
1148 TArrayD a(n-1);
1149 for (UShort_t i = 2; i <= n; i++)
1150 a.fArray[i-2] = (n == 2 ? 0.05 : 0.000001);
7f759bb7 1151 // Make the fit function
2e658fb9 1152 TF1* landaun = MakeNLandauGaus(r->Parameter(kC),
1153 r->Parameter(kDelta),
1154 r->Parameter(kXi),
1155 r->Parameter(kSigma),
1156 r->Parameter(kSigmaN),
1157 n, a.fArray, minE, maxEi);
81775aba 1158 if (minE <= r->Parameter(kDelta) &&
1159 fMaxRange >= r->Parameter(kDelta)) {
1160 // Protect against warning from ParameterSettings
1161 // printf("FitN: Set par limits on Delta: %f, %f\n", minE, fMaxRange);
1162 landaun->SetParLimits(kDelta, minE, fMaxRange); // Delta
1163 }
1164 if (r->Parameter(kXi) >= 0 && r->Parameter(kXi) <= 0.1) {
1165 // printf("FitN: Set par limits on xi: %f, %f\n", 0., 0.1);
1166 landaun->SetParLimits(kXi, 0.00, 0.1); // was fMaxRange - too wide
1167 }
1168 if (r->Parameter(kSigma) >= 1e-5 && r->Parameter(kSigma) <= 0.1) {
1169 // printf("FitN: Set par limits on sigma: %f, %f\n", 1e-5, 0.1);
1170 landaun->SetParLimits(kSigma, 1e-5, 0.1); // was fMaxRange - too wide
1171 }
c389303e 1172 // Check if we're using the noise sigma
1173 if (sigman <= 0) landaun->FixParameter(kSigmaN, 0);
81775aba 1174 else {
1175 // printf("FitN: Set par limits on sigmaN: %f, %f\n", 0., fMaxRange);
1176 landaun->SetParLimits(kSigmaN, 0, fMaxRange);
1177 }
7f759bb7 1178
1179 // Set the range and name of the scale parameters
1180 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
81775aba 1181 if (a[i-2] >= 0 && a[i-2] <= 1) {
1182 // printf("FitN: Set par limits on a_%d: %f, %f\n", i, 0., 1.);
1183 landaun->SetParLimits(kA+i-2, 0,1);
1184 }
7f759bb7 1185 }
1186
1187 // Do the fit
81775aba 1188 if (fDebug)
1189 ::Info("FitNParticle", "Fitting in the range %f,%f (%d)", minE, maxEi, n);
e65b8b56 1190 TFitResultPtr tr = dist->Fit(landaun, FIT_OPTIONS, "", minE, maxEi);
7f759bb7 1191
2e658fb9 1192 // landaun->SetRange(minE, fMaxRange);
7f759bb7 1193 fFitResults.AddAtAndExpand(new TFitResult(*tr), n-1);
1194 fFunctions.AddAtAndExpand(landaun, n-1);
1195
1196 return landaun;
1197}
2e658fb9 1198//____________________________________________________________________
1199TF1*
1200AliForwardUtil::ELossFitter::FitComposite(TH1* dist, Double_t sigman)
1201{
1202 //
1203 // Fit a composite particle signal to the passed energy loss
1204 // distribution
1205 //
1206 // Parameters:
1207 // dist Data to fit the function to
1208 // sigman If larger than zero, the initial guess of the
1209 // detector induced noise. If zero or less, then this
1210 // parameter is ignored in the fit (fixed at 0)
1211 //
1212 // Return:
1213 // The function fitted to the data
1214 //
1215
1216 // Find the fit range
8449e3e0 1217 Int_t cutBin = TMath::Max(dist->GetXaxis()->FindBin(fLowCut),3);
1218 Int_t maxBin = TMath::Min(dist->GetXaxis()->FindBin(fMaxRange),
1219 dist->GetNbinsX());
1220 dist->GetXaxis()->SetRange(cutBin, maxBin);
2e658fb9 1221
1222 // Get the bin with maximum
1223 Int_t peakBin = dist->GetMaximumBin();
1224 Double_t peakE = dist->GetBinLowEdge(peakBin);
1225
1226 // Get the low edge
8449e3e0 1227 // dist->GetXaxis()->SetRangeUser(fLowCut, peakE);
2e658fb9 1228 Int_t minBin = peakBin - fMinusBins; // dist->GetMinimumBin();
1229 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
1230 Double_t maxE = dist->GetBinCenter(peakBin+2*fMinusBins);
1231
1232 // Get the range in bins and the integral of that range
1233 Int_t minEb = dist->GetXaxis()->FindBin(minE);
1234 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
1235 Double_t intg = dist->Integral(minEb, maxEb);
1236 if (intg <= 0) {
1237 ::Warning("Fit1Particle",
1238 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
1239 dist->GetName(), minE, maxE, minEb, maxEb, intg);
1240 return 0;
1241 }
1242
1243 // Restore the range
8449e3e0 1244 dist->GetXaxis()->SetRange(1, maxBin);
2e658fb9 1245
1246 // Define the function to fit
1247 TF1* seed = new TF1("landauSeed", landauGaus1, minE,maxE,kSigmaN+1);
1248
1249 // Set initial guesses, parameter names, and limits
1250 seed->SetParameters(1,peakE,peakE/10,peakE/5,sigman);
1251 seed->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
1252 seed->SetNpx(500);
1253 seed->SetParLimits(kDelta, minE, fMaxRange);
8449e3e0 1254 seed->SetParLimits(kXi, 0.00, 0.1); // Was fMaxRange - too wide
1255 seed->SetParLimits(kSigma, 1e-5, 0.1); // Was fMaxRange - too wide
2e658fb9 1256 if (sigman <= 0) seed->FixParameter(kSigmaN, 0);
1257 else seed->SetParLimits(kSigmaN, 0, fMaxRange);
1258
1259 // Do the fit, getting the result object
81775aba 1260 if (fDebug)
1261 ::Info("FitComposite", "Fitting seed in the range %f,%f", minE, maxE);
e65b8b56 1262 /* TFitResultPtr r = */ dist->Fit(seed, FIT_OPTIONS, "", minE, maxE);
2e658fb9 1263
1264 maxE = dist->GetXaxis()->GetXmax();
1265 TF1* comp = new TF1("composite", landauGausComposite,
1266 minE, maxE, kSigma+1+4);
1267 comp->SetParNames("C", "#Delta_{p}", "#xi", "#sigma",
1268 "C#prime", "#Delta_{p}#prime", "#xi#prime", "#sigma#prim");
1269 comp->SetParameters(0.8 * seed->GetParameter(kC), // 0 Primary weight
1270 seed->GetParameter(kDelta), // 1 Primary Delta
1271 seed->GetParameter(kDelta)/10, // 2 primary Xi
1272 seed->GetParameter(kDelta)/5, // 3 primary sigma
1273 1.20 * seed->GetParameter(kC), // 5 Secondary weight
1274 seed->GetParameter(kDelta), // 6 secondary Delta
1275 seed->GetParameter(kXi), // 7 secondary Xi
1276 seed->GetParameter(kSigma)); // 8 secondary sigma
1277
1278 // comp->SetParLimits(kC, minE, fMaxRange); // C
1279 comp->SetParLimits(kDelta, minE, fMaxRange); // Delta
1280 comp->SetParLimits(kXi, 0.00, fMaxRange); // Xi
1281 comp->SetParLimits(kSigma, 1e-5, fMaxRange); // Sigma
1282 // comp->SetParLimits(kSigma+1, minE, fMaxRange); // C
1283 comp->SetParLimits(kSigma+2, minE/10, fMaxRange); // Delta
1284 comp->SetParLimits(kSigma+3, 0.00, fMaxRange); // Xi
1285 comp->SetParLimits(kSigma+4, 1e-6, fMaxRange); // Sigma
1286 comp->SetLineColor(kRed+1);
1287 comp->SetLineWidth(3);
1288
1289 // Do the fit, getting the result object
81775aba 1290 if (fDebug)
1291 ::Info("FitComposite", "Fitting composite in the range %f,%f", minE, maxE);
e65b8b56 1292 /* TFitResultPtr r = */ dist->Fit(comp, FIT_OPTIONS, "", minE, maxE);
2e658fb9 1293
1294#if 0
1295 TF1* part1 = static_cast<TF1*>(seed->Clone("part1"));
1296 part1->SetLineColor(kGreen+1);
1297 part1->SetLineWidth(4);
1298 part1->SetRange(minE, maxE);
1299 part1->SetParameters(comp->GetParameter(0), // C
1300 comp->GetParameter(1), // Delta
1301 comp->GetParameter(2), // Xi
1302 comp->GetParameter(3), // sigma
1303 0);
1304 part1->Save(minE,maxE,0,0,0,0);
1305 dist->GetListOfFunctions()->Add(part1);
1306
1307 TF1* part2 = static_cast<TF1*>(seed->Clone("part2"));
1308 part2->SetLineColor(kBlue+1);
1309 part2->SetLineWidth(4);
1310 part2->SetRange(minE, maxE);
1311 part2->SetParameters(comp->GetParameter(4), // C
1312 comp->GetParameter(5), // Delta
1313 comp->GetParameter(6), // Xi
1314 comp->GetParameter(7), // sigma
1315 0);
1316 part2->Save(minE,maxE,0,0,0,0);
1317 dist->GetListOfFunctions()->Add(part2);
1318#endif
1319 return comp;
1320}
7e4038b5 1321
1322//====================================================================
1323AliForwardUtil::Histos::~Histos()
1324{
7984e5f7 1325 //
1326 // Destructor
1327 //
b7ab8a2c 1328}
1329
1330//____________________________________________________________________
1331void
1332AliForwardUtil::Histos::Delete(Option_t* opt)
1333{
7e4038b5 1334 if (fFMD1i) delete fFMD1i;
1335 if (fFMD2i) delete fFMD2i;
1336 if (fFMD2o) delete fFMD2o;
1337 if (fFMD3i) delete fFMD3i;
1338 if (fFMD3o) delete fFMD3o;
b7ab8a2c 1339 fFMD1i = 0;
1340 fFMD2i = 0;
1341 fFMD2o = 0;
1342 fFMD3i = 0;
1343 fFMD3o = 0;
1344 TObject::Delete(opt);
7e4038b5 1345}
1346
1347//____________________________________________________________________
1348TH2D*
8449e3e0 1349AliForwardUtil::Histos::Make(UShort_t d, Char_t r, const TAxis& etaAxis)
7e4038b5 1350{
7984e5f7 1351 //
1352 // Make a histogram
1353 //
1354 // Parameters:
1355 // d Detector
1356 // r Ring
1357 // etaAxis Eta axis to use
1358 //
1359 // Return:
1360 // Newly allocated histogram
1361 //
7e4038b5 1362 Int_t ns = (r == 'I' || r == 'i') ? 20 : 40;
8449e3e0 1363 TH2D* hist = 0;
1364 if (etaAxis.GetXbins() && etaAxis.GetXbins()->GetArray())
1365 hist = new TH2D(Form("FMD%d%c_cache", d, r),
1366 Form("FMD%d%c cache", d, r),
1367 etaAxis.GetNbins(), etaAxis.GetXbins()->GetArray(),
1368 ns, 0, TMath::TwoPi());
1369 else
1370 hist = new TH2D(Form("FMD%d%c_cache", d, r),
1371 Form("FMD%d%c cache", d, r),
1372 etaAxis.GetNbins(), etaAxis.GetXmin(),
1373 etaAxis.GetXmax(), ns, 0, TMath::TwoPi());
7e4038b5 1374 hist->SetXTitle("#eta");
1375 hist->SetYTitle("#phi [radians]");
1376 hist->SetZTitle("d^{2}N_{ch}/d#etad#phi");
1377 hist->Sumw2();
1378 hist->SetDirectory(0);
1379
1380 return hist;
1381}
8449e3e0 1382//____________________________________________________________________
1383void
1384AliForwardUtil::Histos::RebinEta(TH2D* hist, const TAxis& etaAxis)
1385{
1386 TAxis* xAxis = hist->GetXaxis();
1387 if (etaAxis.GetXbins() && etaAxis.GetXbins()->GetArray())
1388 xAxis->Set(etaAxis.GetNbins(), etaAxis.GetXbins()->GetArray());
1389 else
1390 xAxis->Set(etaAxis.GetNbins(), etaAxis.GetXmin(), etaAxis.GetXmax());
1391 hist->Rebuild();
1392}
1393
1394
7e4038b5 1395//____________________________________________________________________
1396void
1397AliForwardUtil::Histos::Init(const TAxis& etaAxis)
1398{
7984e5f7 1399 //
1400 // Initialize the object
1401 //
1402 // Parameters:
1403 // etaAxis Eta axis to use
1404 //
7e4038b5 1405 fFMD1i = Make(1, 'I', etaAxis);
1406 fFMD2i = Make(2, 'I', etaAxis);
1407 fFMD2o = Make(2, 'O', etaAxis);
1408 fFMD3i = Make(3, 'I', etaAxis);
1409 fFMD3o = Make(3, 'O', etaAxis);
1410}
8449e3e0 1411//____________________________________________________________________
1412void
1413AliForwardUtil::Histos::ReInit(const TAxis& etaAxis)
1414{
1415 //
1416 // Initialize the object
1417 //
1418 // Parameters:
1419 // etaAxis Eta axis to use
1420 //
1421 RebinEta(fFMD1i, etaAxis);
1422 RebinEta(fFMD2i, etaAxis);
1423 RebinEta(fFMD2o, etaAxis);
1424 RebinEta(fFMD3i, etaAxis);
1425 RebinEta(fFMD3o, etaAxis);
1426}
1427
7e4038b5 1428//____________________________________________________________________
1429void
1430AliForwardUtil::Histos::Clear(Option_t* option)
1431{
7984e5f7 1432 //
1433 // Clear data
1434 //
1435 // Parameters:
1436 // option Not used
1437 //
422a78c8 1438 if (fFMD1i) fFMD1i->Reset(option);
1439 if (fFMD2i) fFMD2i->Reset(option);
1440 if (fFMD2o) fFMD2o->Reset(option);
1441 if (fFMD3i) fFMD3i->Reset(option);
1442 if (fFMD3o) fFMD3o->Reset(option);
7e4038b5 1443}
1444
1445//____________________________________________________________________
1446TH2D*
1447AliForwardUtil::Histos::Get(UShort_t d, Char_t r) const
1448{
7984e5f7 1449 //
1450 // Get the histogram for a particular detector,ring
1451 //
1452 // Parameters:
1453 // d Detector
1454 // r Ring
1455 //
1456 // Return:
1457 // Histogram for detector,ring or nul
1458 //
7e4038b5 1459 switch (d) {
1460 case 1: return fFMD1i;
1461 case 2: return (r == 'I' || r == 'i' ? fFMD2i : fFMD2o);
1462 case 3: return (r == 'I' || r == 'i' ? fFMD3i : fFMD3o);
1463 }
1464 return 0;
1465}
9d99b0dd 1466//====================================================================
1467TList*
1468AliForwardUtil::RingHistos::DefineOutputList(TList* d) const
1469{
7984e5f7 1470 //
1471 // Define the outout list in @a d
1472 //
1473 // Parameters:
1474 // d Where to put the output list
1475 //
1476 // Return:
1477 // Newly allocated TList object or null
1478 //
9d99b0dd 1479 if (!d) return 0;
1480 TList* list = new TList;
5bb5d1f6 1481 list->SetOwner();
9d99b0dd 1482 list->SetName(fName.Data());
1483 d->Add(list);
1484 return list;
1485}
1486//____________________________________________________________________
1487TList*
fb3430ac 1488AliForwardUtil::RingHistos::GetOutputList(const TList* d) const
9d99b0dd 1489{
7984e5f7 1490 //
1491 // Get our output list from the container @a d
1492 //
1493 // Parameters:
1494 // d where to get the output list from
1495 //
1496 // Return:
1497 // The found TList or null
1498 //
9d99b0dd 1499 if (!d) return 0;
1500 TList* list = static_cast<TList*>(d->FindObject(fName.Data()));
1501 return list;
1502}
1503
1504//____________________________________________________________________
1505TH1*
fb3430ac 1506AliForwardUtil::RingHistos::GetOutputHist(const TList* d, const char* name) const
9d99b0dd 1507{
7984e5f7 1508 //
1509 // Find a specific histogram in the source list @a d
1510 //
1511 // Parameters:
1512 // d (top)-container
1513 // name Name of histogram
1514 //
1515 // Return:
1516 // Found histogram or null
1517 //
9d99b0dd 1518 return static_cast<TH1*>(d->FindObject(name));
1519}
1520
f53fb4f6 1521//====================================================================
1522AliForwardUtil::DebugGuard::DebugGuard(Int_t lvl, Int_t msgLvl,
1523 const char* format, ...)
1524 : fMsg("")
1525{
1526 if (lvl < msgLvl) return;
1527 va_list ap;
1528 va_start(ap, format);
81a9a914 1529 Format(fMsg, format, ap);
f53fb4f6 1530 va_end(ap);
81a9a914 1531 Output(+1, fMsg);
f53fb4f6 1532}
1533//____________________________________________________________________
1534AliForwardUtil::DebugGuard::~DebugGuard()
1535{
1536 if (fMsg.IsNull()) return;
81a9a914 1537 Output(-1, fMsg);
1538}
1539//____________________________________________________________________
1540void
1541AliForwardUtil::DebugGuard::Message(Int_t lvl, Int_t msgLvl,
1542 const char* format, ...)
1543{
1544 if (lvl < msgLvl) return;
1545 TString msg;
1546 va_list ap;
1547 va_start(ap, format);
1548 Format(msg, format, ap);
1549 va_end(ap);
1550 Output(0, msg);
1551}
1552
1553//____________________________________________________________________
1554void
1555AliForwardUtil::DebugGuard::Format(TString& out, const char* format, va_list ap)
1556{
1557 static char buf[512];
1558 Int_t n = gROOT->GetDirLevel() + 2;
1559 for (Int_t i = 0; i < n; i++) buf[i] = ' ';
1560 vsnprintf(&(buf[n]), 511-n, format, ap);
1561 buf[511] = '\0';
1562 out = buf;
f53fb4f6 1563}
1564//____________________________________________________________________
1565void
81a9a914 1566AliForwardUtil::DebugGuard::Output(int in, TString& msg)
f53fb4f6 1567{
81a9a914 1568 msg[0] = (in > 0 ? '>' : in < 0 ? '<' : '=');
1569 AliLog::Message(AliLog::kInfo, msg, 0, 0, "PWGLF/forward", 0, 0);
1570 if (in > 0) gROOT->IncreaseDirLevel();
1571 else if (in < 0) gROOT->DecreaseDirLevel();
f53fb4f6 1572}
1573
1574
1575
7e4038b5 1576//
1577// EOF
1578//