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