]>
Commit | Line | Data |
---|---|---|
f8715167 | 1 | // |
2 | // Class to do the energy correction of FMD ESD data | |
3 | // | |
4 | #include "AliFMDEnergyFitter.h" | |
0bd4b00f | 5 | #include "AliForwardCorrectionManager.h" |
f8715167 | 6 | #include <AliESDFMD.h> |
7 | #include <TAxis.h> | |
8 | #include <TList.h> | |
9 | #include <TH1.h> | |
10 | #include <TF1.h> | |
11 | #include <TMath.h> | |
f8715167 | 12 | #include <AliLog.h> |
13 | #include <TClonesArray.h> | |
14 | #include <TFitResult.h> | |
15 | #include <THStack.h> | |
0bd4b00f | 16 | #include <TROOT.h> |
17 | #include <iostream> | |
18 | #include <iomanip> | |
f8715167 | 19 | |
20 | ClassImp(AliFMDEnergyFitter) | |
21 | #if 0 | |
22 | ; // This is for Emacs | |
23 | #endif | |
0bd4b00f | 24 | namespace { |
25 | const char* fgkEDistFormat = "%s_etabin%03d"; | |
26 | } | |
f8715167 | 27 | |
f8715167 | 28 | |
29 | //____________________________________________________________________ | |
30 | AliFMDEnergyFitter::AliFMDEnergyFitter() | |
31 | : TNamed(), | |
32 | fRingHistos(), | |
9d05ffeb | 33 | fLowCut(0.4), |
34 | fNParticles(5), | |
35 | fMinEntries(1000), | |
c389303e | 36 | fFitRangeBinWidth(4), |
f8715167 | 37 | fDoFits(false), |
0bd4b00f | 38 | fDoMakeObject(false), |
f8715167 | 39 | fEtaAxis(), |
5e4d905e | 40 | fCentralityAxis(), |
4b9857f3 | 41 | fMaxE(10), |
42 | fNEbins(300), | |
43 | fUseIncreasingBins(true), | |
c389303e | 44 | fMaxRelParError(.25), |
45 | fMaxChi2PerNDF(20), | |
0bd4b00f | 46 | fMinWeight(1e-7), |
f8715167 | 47 | fDebug(0) |
7984e5f7 | 48 | { |
49 | // | |
50 | // Default Constructor - do not use | |
51 | // | |
52 | } | |
f8715167 | 53 | |
54 | //____________________________________________________________________ | |
55 | AliFMDEnergyFitter::AliFMDEnergyFitter(const char* title) | |
56 | : TNamed("fmdEnergyFitter", title), | |
57 | fRingHistos(), | |
9d05ffeb | 58 | fLowCut(0.4), |
59 | fNParticles(5), | |
60 | fMinEntries(1000), | |
c389303e | 61 | fFitRangeBinWidth(4), |
f8715167 | 62 | fDoFits(false), |
0bd4b00f | 63 | fDoMakeObject(false), |
4b9857f3 | 64 | fEtaAxis(0,0,0), |
5e4d905e | 65 | fCentralityAxis(0,0,0), |
4b9857f3 | 66 | fMaxE(10), |
67 | fNEbins(300), | |
68 | fUseIncreasingBins(true), | |
c389303e | 69 | fMaxRelParError(.25), |
0bd4b00f | 70 | fMaxChi2PerNDF(20), |
71 | fMinWeight(1e-7), | |
f8715167 | 72 | fDebug(3) |
73 | { | |
7984e5f7 | 74 | // |
75 | // Constructor | |
76 | // | |
77 | // Parameters: | |
78 | // title Title of object - not significant | |
79 | // | |
f8715167 | 80 | fEtaAxis.SetName("etaAxis"); |
81 | fEtaAxis.SetTitle("#eta"); | |
5e4d905e | 82 | fCentralityAxis.SetName("centralityAxis"); |
83 | fCentralityAxis.SetTitle("Centrality [%]"); | |
f8715167 | 84 | fRingHistos.Add(new RingHistos(1, 'I')); |
85 | fRingHistos.Add(new RingHistos(2, 'I')); | |
86 | fRingHistos.Add(new RingHistos(2, 'O')); | |
87 | fRingHistos.Add(new RingHistos(3, 'I')); | |
88 | fRingHistos.Add(new RingHistos(3, 'O')); | |
89 | } | |
90 | ||
91 | //____________________________________________________________________ | |
92 | AliFMDEnergyFitter::AliFMDEnergyFitter(const AliFMDEnergyFitter& o) | |
93 | : TNamed(o), | |
94 | fRingHistos(), | |
95 | fLowCut(o.fLowCut), | |
c389303e | 96 | fNParticles(o.fNParticles), |
f8715167 | 97 | fMinEntries(o.fMinEntries), |
c389303e | 98 | fFitRangeBinWidth(o.fFitRangeBinWidth), |
f8715167 | 99 | fDoFits(o.fDoFits), |
0bd4b00f | 100 | fDoMakeObject(o.fDoMakeObject), |
f8715167 | 101 | fEtaAxis(o.fEtaAxis), |
5e4d905e | 102 | fCentralityAxis(o.fCentralityAxis), |
4b9857f3 | 103 | fMaxE(o.fMaxE), |
104 | fNEbins(o.fNEbins), | |
105 | fUseIncreasingBins(o.fUseIncreasingBins), | |
c389303e | 106 | fMaxRelParError(o.fMaxRelParError), |
107 | fMaxChi2PerNDF(o.fMaxChi2PerNDF), | |
0bd4b00f | 108 | fMinWeight(o.fMinWeight), |
f8715167 | 109 | fDebug(o.fDebug) |
110 | { | |
7984e5f7 | 111 | // |
112 | // Copy constructor | |
113 | // | |
114 | // Parameters: | |
115 | // o Object to copy from | |
116 | // | |
f8715167 | 117 | TIter next(&o.fRingHistos); |
118 | TObject* obj = 0; | |
119 | while ((obj = next())) fRingHistos.Add(obj); | |
120 | } | |
121 | ||
122 | //____________________________________________________________________ | |
123 | AliFMDEnergyFitter::~AliFMDEnergyFitter() | |
124 | { | |
7984e5f7 | 125 | // |
126 | // Destructor | |
127 | // | |
f8715167 | 128 | fRingHistos.Delete(); |
129 | } | |
130 | ||
131 | //____________________________________________________________________ | |
132 | AliFMDEnergyFitter& | |
133 | AliFMDEnergyFitter::operator=(const AliFMDEnergyFitter& o) | |
134 | { | |
7984e5f7 | 135 | // |
136 | // Assignment operator | |
137 | // | |
138 | // Parameters: | |
139 | // o Object to assign from | |
140 | // | |
141 | // Return: | |
142 | // Reference to this | |
143 | // | |
f8715167 | 144 | TNamed::operator=(o); |
145 | ||
146 | fLowCut = o.fLowCut; | |
c389303e | 147 | fNParticles = o.fNParticles; |
f8715167 | 148 | fMinEntries = o.fMinEntries; |
c389303e | 149 | fFitRangeBinWidth= o.fFitRangeBinWidth; |
f8715167 | 150 | fDoFits = o.fDoFits; |
0bd4b00f | 151 | fDoMakeObject = o.fDoMakeObject; |
5e4d905e | 152 | fEtaAxis.Set(o.fEtaAxis.GetNbins(), |
153 | o.fEtaAxis.GetXmin(), | |
154 | o.fEtaAxis.GetXmax()); | |
155 | if (o.fCentralityAxis.GetXbins()) { | |
156 | const TArrayD* bins = o.fCentralityAxis.GetXbins(); | |
157 | fCentralityAxis.Set(bins->GetSize()-1,bins->GetArray()); | |
158 | } | |
159 | else | |
160 | fCentralityAxis.Set(o.fCentralityAxis.GetNbins(), | |
161 | o.fCentralityAxis.GetXmin(), | |
162 | o.fCentralityAxis.GetXmax()); | |
f8715167 | 163 | fDebug = o.fDebug; |
0bd4b00f | 164 | fMaxRelParError= o.fMaxRelParError; |
165 | fMaxChi2PerNDF = o.fMaxChi2PerNDF; | |
166 | fMinWeight = o.fMinWeight; | |
f8715167 | 167 | |
168 | fRingHistos.Delete(); | |
169 | TIter next(&o.fRingHistos); | |
170 | TObject* obj = 0; | |
171 | while ((obj = next())) fRingHistos.Add(obj); | |
172 | ||
173 | return *this; | |
174 | } | |
175 | ||
176 | //____________________________________________________________________ | |
177 | AliFMDEnergyFitter::RingHistos* | |
178 | AliFMDEnergyFitter::GetRingHistos(UShort_t d, Char_t r) const | |
179 | { | |
7984e5f7 | 180 | // |
181 | // Get the ring histogram container | |
182 | // | |
183 | // Parameters: | |
184 | // d Detector | |
185 | // r Ring | |
186 | // | |
187 | // Return: | |
188 | // Ring histogram container | |
189 | // | |
f8715167 | 190 | Int_t idx = -1; |
191 | switch (d) { | |
192 | case 1: idx = 0; break; | |
193 | case 2: idx = 1 + (r == 'I' || r == 'i' ? 0 : 1); break; | |
194 | case 3: idx = 3 + (r == 'I' || r == 'i' ? 0 : 1); break; | |
195 | } | |
196 | if (idx < 0 || idx >= fRingHistos.GetEntries()) return 0; | |
197 | ||
198 | return static_cast<RingHistos*>(fRingHistos.At(idx)); | |
199 | } | |
200 | ||
201 | //____________________________________________________________________ | |
202 | void | |
203 | AliFMDEnergyFitter::Init(const TAxis& eAxis) | |
204 | { | |
7984e5f7 | 205 | // |
206 | // Initialise the task | |
207 | // | |
208 | // Parameters: | |
209 | // etaAxis The eta axis to use. Note, that if the eta axis | |
210 | // has already been set (using SetEtaAxis), then this parameter will be | |
211 | // ignored | |
212 | // | |
4b9857f3 | 213 | if (fEtaAxis.GetNbins() == 0 || |
7c1a1f1d | 214 | TMath::Abs(fEtaAxis.GetXmax() - fEtaAxis.GetXmin()) < 1e-7) |
4b9857f3 | 215 | SetEtaAxis(eAxis); |
5e4d905e | 216 | if (fCentralityAxis.GetNbins() == 0) { |
217 | UShort_t n = 12; | |
218 | Double_t bins[] = { 0., 5., 10., 15., 20., 30., | |
219 | 40., 50., 60., 70., 80., 100. }; | |
220 | SetCentralityAxis(n, bins); | |
221 | } | |
f8715167 | 222 | TIter next(&fRingHistos); |
223 | RingHistos* o = 0; | |
224 | while ((o = static_cast<RingHistos*>(next()))) | |
5e4d905e | 225 | o->Init(fEtaAxis, fCentralityAxis, fMaxE, fNEbins, fUseIncreasingBins); |
f8715167 | 226 | } |
4b9857f3 | 227 | //____________________________________________________________________ |
228 | void | |
229 | AliFMDEnergyFitter::SetEtaAxis(const TAxis& eAxis) | |
230 | { | |
7984e5f7 | 231 | // |
232 | // Set the eta axis to use. This will force the code to use this | |
233 | // eta axis definition - irrespective of whatever axis is passed to | |
234 | // the Init member function. Therefore, this member function can be | |
235 | // used to force another eta axis than one found in the correction | |
236 | // objects. | |
237 | // | |
238 | // Parameters: | |
239 | // etaAxis Eta axis to use | |
240 | // | |
4b9857f3 | 241 | SetEtaAxis(eAxis.GetNbins(),eAxis.GetXmin(),eAxis.GetXmax()); |
242 | } | |
243 | //____________________________________________________________________ | |
244 | void | |
245 | AliFMDEnergyFitter::SetEtaAxis(Int_t nBins, Double_t etaMin, Double_t etaMax) | |
246 | { | |
7984e5f7 | 247 | // |
248 | // Set the eta axis to use. This will force the code to use this | |
249 | // eta axis definition - irrespective of whatever axis is passed to | |
250 | // the Init member function. Therefore, this member function can be | |
251 | // used to force another eta axis than one found in the correction | |
252 | // objects. | |
253 | // | |
254 | // Parameters: | |
255 | // nBins Number of bins | |
256 | // etaMin Minimum of the eta axis | |
257 | // etaMax Maximum of the eta axis | |
258 | // | |
4b9857f3 | 259 | fEtaAxis.Set(nBins,etaMin,etaMax); |
260 | } | |
5e4d905e | 261 | //____________________________________________________________________ |
262 | void | |
263 | AliFMDEnergyFitter::SetCentralityAxis(UShort_t n, Double_t* bins) | |
264 | { | |
265 | fCentralityAxis.Set(n-1, bins); | |
266 | } | |
267 | ||
4b9857f3 | 268 | |
f8715167 | 269 | //____________________________________________________________________ |
270 | Bool_t | |
5e4d905e | 271 | AliFMDEnergyFitter::Accumulate(const AliESDFMD& input, |
272 | Double_t cent, | |
f8715167 | 273 | Bool_t empty) |
274 | { | |
7984e5f7 | 275 | // |
276 | // Fitter the input AliESDFMD object | |
277 | // | |
278 | // Parameters: | |
279 | // input Input | |
5e4d905e | 280 | // cent Centrality |
7984e5f7 | 281 | // empty Whether the event is 'empty' |
282 | // | |
283 | // Return: | |
284 | // True on success, false otherwise | |
285 | // | |
5e4d905e | 286 | Int_t icent = fCentralityAxis.FindBin(cent); |
287 | if (icent < 1 || icent > fCentralityAxis.GetNbins()) icent = 0; | |
288 | ||
f8715167 | 289 | for(UShort_t d = 1; d <= 3; d++) { |
290 | Int_t nRings = (d == 1 ? 1 : 2); | |
291 | for (UShort_t q = 0; q < nRings; q++) { | |
292 | Char_t r = (q == 0 ? 'I' : 'O'); | |
293 | UShort_t nsec = (q == 0 ? 20 : 40); | |
294 | UShort_t nstr = (q == 0 ? 512 : 256); | |
295 | ||
296 | RingHistos* histos = GetRingHistos(d, r); | |
297 | ||
298 | for(UShort_t s = 0; s < nsec; s++) { | |
299 | for(UShort_t t = 0; t < nstr; t++) { | |
300 | Float_t mult = input.Multiplicity(d,r,s,t); | |
301 | ||
302 | // Keep dead-channel information. | |
303 | if(mult == AliESDFMD::kInvalidMult || mult > 10 || mult <= 0) | |
304 | continue; | |
305 | ||
306 | // Get the pseudo-rapidity | |
307 | Double_t eta1 = input.Eta(d,r,s,t); | |
308 | Int_t ieta = fEtaAxis.FindBin(eta1); | |
309 | if (ieta < 1 || ieta > fEtaAxis.GetNbins()) continue; | |
310 | ||
5e4d905e | 311 | histos->Fill(empty, ieta-1, icent, mult); |
f8715167 | 312 | |
313 | } // for strip | |
314 | } // for sector | |
315 | } // for ring | |
316 | } // for detector | |
317 | ||
318 | return kTRUE; | |
319 | } | |
320 | ||
321 | //____________________________________________________________________ | |
322 | void | |
7c1a1f1d | 323 | AliFMDEnergyFitter::Fit(const TList* dir) |
f8715167 | 324 | { |
7984e5f7 | 325 | // |
326 | // Scale the histograms to the total number of events | |
327 | // | |
328 | // Parameters: | |
329 | // dir Where the histograms are | |
330 | // | |
f8715167 | 331 | if (!fDoFits) return; |
332 | ||
333 | TList* d = static_cast<TList*>(dir->FindObject(GetName())); | |
334 | if (!d) return; | |
335 | ||
336 | // +1 for chi^2 | |
337 | // +3 for 1 landau | |
338 | // +1 for N | |
c389303e | 339 | // +fNParticles-1 for weights |
340 | Int_t nStack = kN+fNParticles; | |
f8715167 | 341 | THStack* stack[nStack]; |
c389303e | 342 | stack[0] = new THStack("chi2", "#chi^{2}/#nu"); |
343 | stack[kC +1] = new THStack("c", "Constant"); | |
344 | stack[kDelta +1] = new THStack("delta", "#Delta_{p}"); | |
345 | stack[kXi +1] = new THStack("xi", "#xi"); | |
346 | stack[kSigma +1] = new THStack("sigma", "#sigma"); | |
347 | stack[kSigmaN+1] = new THStack("sigman", "#sigma_{n}"); | |
348 | stack[kN +1] = new THStack("n", "# Particles"); | |
349 | for (Int_t i = 2; i <= fNParticles; i++) | |
350 | stack[kN+i] = new THStack(Form("a%d", i), Form("a_{%d}", i)); | |
f8715167 | 351 | for (Int_t i = 0; i < nStack; i++) |
352 | d->Add(stack[i]); | |
353 | ||
354 | TIter next(&fRingHistos); | |
355 | RingHistos* o = 0; | |
356 | while ((o = static_cast<RingHistos*>(next()))) { | |
c389303e | 357 | TObjArray* l = o->Fit(d, fEtaAxis, fLowCut, fNParticles, |
358 | fMinEntries, fFitRangeBinWidth, | |
359 | fMaxRelParError, fMaxChi2PerNDF); | |
f8715167 | 360 | if (!l) continue; |
361 | for (Int_t i = 0; i < l->GetEntriesFast(); i++) { | |
362 | stack[i % nStack]->Add(static_cast<TH1*>(l->At(i))); | |
363 | } | |
364 | } | |
0bd4b00f | 365 | |
366 | if (!fDoMakeObject) return; | |
367 | ||
368 | MakeCorrectionsObject(d); | |
369 | } | |
370 | ||
371 | //____________________________________________________________________ | |
372 | void | |
373 | AliFMDEnergyFitter::MakeCorrectionsObject(TList* d) | |
374 | { | |
7984e5f7 | 375 | // |
376 | // Generate the corrections object | |
377 | // | |
378 | // Parameters: | |
379 | // dir List to analyse | |
380 | // | |
0bd4b00f | 381 | AliForwardCorrectionManager& mgr = AliForwardCorrectionManager::Instance(); |
382 | ||
383 | AliFMDCorrELossFit* obj = new AliFMDCorrELossFit; | |
384 | obj->SetEtaAxis(fEtaAxis); | |
385 | obj->SetLowCut(fLowCut); | |
386 | ||
387 | TIter next(&fRingHistos); | |
388 | RingHistos* o = 0; | |
389 | while ((o = static_cast<RingHistos*>(next()))) { | |
390 | o->FindBestFits(d, *obj, fEtaAxis, fMaxRelParError, | |
391 | fMaxChi2PerNDF, fMinWeight); | |
392 | } | |
393 | ||
394 | TString oName(mgr.GetObjectName(AliForwardCorrectionManager::kELossFits)); | |
395 | TString fileName(mgr.GetFilePath(AliForwardCorrectionManager::kELossFits)); | |
396 | AliInfo(Form("Object %s created in output - should be extracted and copied " | |
397 | "to %s", oName.Data(), fileName.Data())); | |
f7cfc454 | 398 | d->Add(new TNamed("filename", fileName.Data())); |
0bd4b00f | 399 | d->Add(obj, oName.Data()); |
f8715167 | 400 | } |
401 | ||
402 | //____________________________________________________________________ | |
403 | void | |
404 | AliFMDEnergyFitter::DefineOutput(TList* dir) | |
405 | { | |
7984e5f7 | 406 | // |
407 | // Define the output histograms. These are put in a sub list of the | |
408 | // passed list. The histograms are merged before the parent task calls | |
409 | // AliAnalysisTaskSE::Terminate | |
410 | // | |
411 | // Parameters: | |
412 | // dir Directory to add to | |
413 | // | |
f8715167 | 414 | TList* d = new TList; |
415 | d->SetName(GetName()); | |
416 | dir->Add(d); | |
417 | d->Add(&fEtaAxis); | |
418 | TIter next(&fRingHistos); | |
419 | RingHistos* o = 0; | |
420 | while ((o = static_cast<RingHistos*>(next()))) { | |
421 | o->Output(d); | |
422 | } | |
423 | } | |
424 | //____________________________________________________________________ | |
425 | void | |
426 | AliFMDEnergyFitter::SetDebug(Int_t dbg) | |
427 | { | |
7984e5f7 | 428 | // |
429 | // Set the debug level. The higher the value the more output | |
430 | // | |
431 | // Parameters: | |
432 | // dbg Debug level | |
433 | // | |
f8715167 | 434 | fDebug = dbg; |
435 | TIter next(&fRingHistos); | |
436 | RingHistos* o = 0; | |
437 | while ((o = static_cast<RingHistos*>(next()))) | |
438 | o->fDebug = dbg; | |
439 | } | |
0bd4b00f | 440 | |
441 | //____________________________________________________________________ | |
442 | void | |
443 | AliFMDEnergyFitter::Print(Option_t*) const | |
444 | { | |
7984e5f7 | 445 | // |
446 | // Print information | |
447 | // | |
448 | // Parameters: | |
449 | // option Not used | |
450 | // | |
0bd4b00f | 451 | char ind[gROOT->GetDirLevel()+1]; |
452 | for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' '; | |
453 | ind[gROOT->GetDirLevel()] = '\0'; | |
1f480471 | 454 | std::cout << ind << ClassName() << ": " << GetName() << '\n' |
0bd4b00f | 455 | << ind << " Low cut: " << fLowCut << " E/E_mip\n" |
456 | << ind << " Max(particles): " << fNParticles << '\n' | |
457 | << ind << " Min(entries): " << fMinEntries << '\n' | |
458 | << ind << " Fit range: " | |
459 | << fFitRangeBinWidth << " bins\n" | |
460 | << ind << " Make fits: " | |
461 | << (fDoFits ? "yes\n" : "no\n") | |
462 | << ind << " Make object: " | |
463 | << (fDoMakeObject ? "yes\n" : "no\n") | |
464 | << ind << " Max E/E_mip: " << fMaxE << '\n' | |
465 | << ind << " N bins: " << fNEbins << '\n' | |
466 | << ind << " Increasing bins: " | |
467 | << (fUseIncreasingBins ?"yes\n" : "no\n") | |
468 | << ind << " max(delta p/p): " << fMaxRelParError << '\n' | |
469 | << ind << " max(chi^2/nu): " << fMaxChi2PerNDF << '\n' | |
470 | << ind << " min(a_i): " << fMinWeight << std::endl; | |
471 | } | |
f8715167 | 472 | |
473 | //==================================================================== | |
474 | AliFMDEnergyFitter::RingHistos::RingHistos() | |
475 | : AliForwardUtil::RingHistos(), | |
476 | fEDist(0), | |
477 | fEmpty(0), | |
478 | fEtaEDists(), | |
479 | fList(0), | |
0bd4b00f | 480 | fFits("AliFMDCorrELossFit::ELossFit"), |
f8715167 | 481 | fDebug(0) |
7984e5f7 | 482 | { |
483 | // | |
484 | // Default CTOR | |
485 | // | |
486 | } | |
f8715167 | 487 | |
488 | //____________________________________________________________________ | |
489 | AliFMDEnergyFitter::RingHistos::RingHistos(UShort_t d, Char_t r) | |
490 | : AliForwardUtil::RingHistos(d,r), | |
491 | fEDist(0), | |
492 | fEmpty(0), | |
493 | fEtaEDists(), | |
494 | fList(0), | |
0bd4b00f | 495 | fFits("AliFMDCorrELossFit::ELossFit"), |
f8715167 | 496 | fDebug(0) |
497 | { | |
7984e5f7 | 498 | // |
499 | // Constructor | |
500 | // | |
501 | // Parameters: | |
502 | // d detector | |
503 | // r ring | |
504 | // | |
f8715167 | 505 | fEtaEDists.SetName("EDists"); |
506 | } | |
507 | //____________________________________________________________________ | |
508 | AliFMDEnergyFitter::RingHistos::RingHistos(const RingHistos& o) | |
509 | : AliForwardUtil::RingHistos(o), | |
510 | fEDist(o.fEDist), | |
511 | fEmpty(o.fEmpty), | |
512 | fEtaEDists(), | |
513 | fList(0), | |
0bd4b00f | 514 | fFits("AliFMDCorrELossFit::ELossFit"), |
f8715167 | 515 | fDebug(0) |
516 | { | |
7984e5f7 | 517 | // |
518 | // Copy constructor | |
519 | // | |
520 | // Parameters: | |
521 | // o Object to copy from | |
522 | // | |
0bd4b00f | 523 | fFits.Clear(); |
f8715167 | 524 | TIter next(&o.fEtaEDists); |
525 | TObject* obj = 0; | |
526 | while ((obj = next())) fEtaEDists.Add(obj->Clone()); | |
527 | if (o.fList) { | |
528 | fList = new TList; | |
529 | fList->SetName(fName); | |
530 | TIter next2(o.fList); | |
531 | while ((obj = next2())) fList->Add(obj->Clone()); | |
532 | } | |
533 | } | |
534 | ||
535 | //____________________________________________________________________ | |
536 | AliFMDEnergyFitter::RingHistos& | |
537 | AliFMDEnergyFitter::RingHistos::operator=(const RingHistos& o) | |
538 | { | |
7984e5f7 | 539 | // |
540 | // Assignment operator | |
541 | // | |
542 | // Parameters: | |
543 | // o Object to assign from | |
544 | // | |
545 | // Return: | |
546 | // Reference to this | |
547 | // | |
f8715167 | 548 | AliForwardUtil::RingHistos::operator=(o); |
549 | ||
550 | if (fEDist) delete fEDist; | |
551 | if (fEmpty) delete fEmpty; | |
552 | fEtaEDists.Delete(); | |
553 | if (fList) fList->Delete(); | |
0bd4b00f | 554 | fFits.Clear(); |
f8715167 | 555 | |
556 | fEDist = static_cast<TH1D*>(o.fEDist->Clone()); | |
557 | fEmpty = static_cast<TH1D*>(o.fEmpty->Clone()); | |
558 | ||
559 | TIter next(&o.fEtaEDists); | |
560 | TObject* obj = 0; | |
561 | while ((obj = next())) fEtaEDists.Add(obj->Clone()); | |
562 | ||
563 | if (o.fList) { | |
564 | fList = new TList; | |
565 | fList->SetName(fName); | |
566 | TIter next2(o.fList); | |
567 | while ((obj = next2())) fList->Add(obj->Clone()); | |
568 | } | |
569 | ||
570 | return *this; | |
571 | } | |
572 | //____________________________________________________________________ | |
573 | AliFMDEnergyFitter::RingHistos::~RingHistos() | |
574 | { | |
7984e5f7 | 575 | // |
576 | // Destructor | |
577 | // | |
f8715167 | 578 | if (fEDist) delete fEDist; |
579 | fEtaEDists.Delete(); | |
580 | } | |
581 | ||
582 | //____________________________________________________________________ | |
583 | void | |
5e4d905e | 584 | AliFMDEnergyFitter::RingHistos::Fill(Bool_t empty, Int_t ieta, |
585 | Int_t /* icent */, Double_t mult) | |
f8715167 | 586 | { |
7984e5f7 | 587 | // |
588 | // Fill histogram | |
589 | // | |
590 | // Parameters: | |
591 | // empty True if event is empty | |
5e4d905e | 592 | // ieta Eta bin (0-based) |
593 | // icent Centrality bin (1-based) | |
7984e5f7 | 594 | // mult Signal |
595 | // | |
f8715167 | 596 | if (empty) { |
597 | fEmpty->Fill(mult); | |
598 | return; | |
599 | } | |
600 | fEDist->Fill(mult); | |
601 | ||
5e4d905e | 602 | // Here, we should first look up in a centrality array, and then in |
603 | // that array look up the eta bin - or perhaps we should do it the | |
604 | // other way around? | |
f8715167 | 605 | if (ieta < 0 || ieta >= fEtaEDists.GetEntries()) return; |
606 | ||
607 | TH1D* h = static_cast<TH1D*>(fEtaEDists.At(ieta)); | |
608 | if (!h) return; | |
609 | ||
610 | h->Fill(mult); | |
611 | } | |
612 | ||
613 | //__________________________________________________________________ | |
614 | TArrayD | |
66b34429 | 615 | AliFMDEnergyFitter::RingHistos::MakeIncreasingAxis(Int_t n, Double_t min, |
616 | Double_t max) const | |
f8715167 | 617 | { |
7984e5f7 | 618 | // |
619 | // Make an axis with increasing bins | |
620 | // | |
621 | // Parameters: | |
622 | // n Number of bins | |
623 | // min Minimum | |
624 | // max Maximum | |
625 | // | |
626 | // Return: | |
627 | // An axis with quadratically increasing bin size | |
628 | // | |
629 | ||
f8715167 | 630 | TArrayD bins(n+1); |
631 | Double_t dx = (max-min) / n; | |
632 | bins[0] = min; | |
633 | Int_t i = 1; | |
634 | for (i = 1; i < n+1; i++) { | |
635 | Double_t dI = float(i)/n; | |
66b34429 | 636 | Double_t next = bins[i-1] + dx + dI * dI * dx; |
f8715167 | 637 | bins[i] = next; |
638 | if (next > max) break; | |
639 | } | |
640 | bins.Set(i+1); | |
641 | return bins; | |
642 | } | |
643 | ||
644 | //____________________________________________________________________ | |
645 | void | |
c389303e | 646 | AliFMDEnergyFitter::RingHistos::Make(Int_t ieta, |
647 | Double_t emin, | |
648 | Double_t emax, | |
649 | Double_t deMax, | |
650 | Int_t nDeBins, | |
651 | Bool_t incr) | |
f8715167 | 652 | { |
7984e5f7 | 653 | // |
654 | // Make E/E_mip histogram | |
655 | // | |
656 | // Parameters: | |
657 | // ieta Eta bin | |
658 | // eMin Least signal | |
659 | // eMax Largest signal | |
660 | // deMax Maximum energy loss | |
661 | // nDeBins Number energy loss bins | |
662 | // incr Whether to make bins of increasing size | |
663 | // | |
f8715167 | 664 | TH1D* h = 0; |
0bd4b00f | 665 | TString name = Form(fgkEDistFormat, fName.Data(), ieta); |
f8715167 | 666 | TString title = Form("#DeltaE/#DeltaE_{mip} for %s %+5.3f#leq#eta<%+5.3f " |
667 | "(#eta bin %d)", fName.Data(), emin, emax, ieta); | |
668 | if (!incr) | |
669 | h = new TH1D(name.Data(), title.Data(), nDeBins, 0, deMax); | |
670 | else { | |
671 | TArrayD deAxis = MakeIncreasingAxis(nDeBins, 0, deMax); | |
672 | h = new TH1D(name.Data(), title.Data(), deAxis.fN-1, deAxis.fArray); | |
673 | } | |
674 | ||
675 | h->SetDirectory(0); | |
676 | h->SetXTitle("#DeltaE/#DeltaE_{mip}"); | |
677 | h->SetFillColor(Color()); | |
678 | h->SetMarkerColor(Color()); | |
679 | h->SetLineColor(Color()); | |
680 | h->SetFillStyle(3001); | |
681 | h->Sumw2(); | |
682 | ||
683 | fEtaEDists.AddAt(h, ieta-1); | |
684 | } | |
685 | //____________________________________________________________________ | |
c389303e | 686 | TH1D* AliFMDEnergyFitter::RingHistos::MakePar(const char* name, |
687 | const char* title, | |
688 | const TAxis& eta) const | |
f8715167 | 689 | { |
7984e5f7 | 690 | // |
691 | // Make a parameter histogram | |
692 | // | |
693 | // Parameters: | |
694 | // name Name of histogram. | |
695 | // title Title of histogram. | |
696 | // eta Eta axis | |
697 | // | |
698 | // Return: | |
699 | // | |
700 | // | |
f8715167 | 701 | TH1D* h = new TH1D(Form("%s_%s", fName.Data(), name), |
702 | Form("%s for %s", title, fName.Data()), | |
703 | eta.GetNbins(), eta.GetXmin(), eta.GetXmax()); | |
704 | h->SetXTitle("#eta"); | |
705 | h->SetYTitle(title); | |
706 | h->SetDirectory(0); | |
707 | h->SetFillColor(Color()); | |
708 | h->SetMarkerColor(Color()); | |
709 | h->SetLineColor(Color()); | |
710 | h->SetFillStyle(3001); | |
711 | h->Sumw2(); | |
712 | ||
713 | return h; | |
714 | } | |
715 | //____________________________________________________________________ | |
716 | TH1D* | |
717 | AliFMDEnergyFitter::RingHistos::MakeTotal(const char* name, | |
718 | const char* title, | |
719 | const TAxis& eta, | |
720 | Int_t low, | |
721 | Int_t high, | |
722 | Double_t val, | |
723 | Double_t err) const | |
724 | { | |
7984e5f7 | 725 | // |
726 | // Make a histogram that contains the results of the fit over the full ring | |
727 | // | |
728 | // Parameters: | |
729 | // name Name | |
730 | // title Title | |
731 | // eta Eta axis | |
732 | // low Least bin | |
733 | // high Largest bin | |
734 | // val Value of parameter | |
735 | // err Error on parameter | |
736 | // | |
737 | // Return: | |
738 | // The newly allocated histogram | |
739 | // | |
f8715167 | 740 | Double_t xlow = eta.GetBinLowEdge(low); |
741 | Double_t xhigh = eta.GetBinUpEdge(high); | |
742 | TH1D* h = new TH1D(Form("%s_%s", fName.Data(), name), | |
743 | Form("%s for %s", title, fName.Data()), | |
744 | 1, xlow, xhigh); | |
745 | h->SetBinContent(1, val); | |
746 | h->SetBinError(1, err); | |
747 | h->SetXTitle("#eta"); | |
748 | h->SetYTitle(title); | |
749 | h->SetDirectory(0); | |
750 | h->SetFillColor(0); | |
751 | h->SetMarkerColor(Color()); | |
752 | h->SetLineColor(Color()); | |
753 | h->SetFillStyle(0); | |
754 | h->SetLineStyle(2); | |
755 | h->SetLineWidth(2); | |
756 | ||
757 | return h; | |
758 | } | |
759 | ||
760 | //____________________________________________________________________ | |
761 | void | |
762 | AliFMDEnergyFitter::RingHistos::Init(const TAxis& eAxis, | |
5e4d905e | 763 | const TAxis& /* cAxis */, |
f8715167 | 764 | Double_t maxDE, Int_t nDEbins, |
765 | Bool_t useIncrBin) | |
766 | { | |
7984e5f7 | 767 | // |
768 | // Initialise object | |
769 | // | |
770 | // Parameters: | |
771 | // eAxis Eta axis | |
772 | // maxDE Max energy loss to consider | |
773 | // nDEbins Number of bins | |
774 | // useIncrBin Whether to use an increasing bin size | |
775 | // | |
f8715167 | 776 | fEDist = new TH1D(Form("%s_edist", fName.Data()), |
777 | Form("#DeltaE/#DeltaE_{mip} for %s", fName.Data()), | |
778 | 200, 0, 6); | |
779 | fEmpty = new TH1D(Form("%s_empty", fName.Data()), | |
780 | Form("#DeltaE/#DeltaE_{mip} for %s (empty events)", | |
781 | fName.Data()), 200, 0, 6); | |
782 | fList->Add(fEDist); | |
783 | fList->Add(fEmpty); | |
5e4d905e | 784 | // Here, we should make an array of centrality bins ... |
785 | // In that case, the structure will be | |
786 | // | |
787 | // -+- Ring1 -+- Centrality1 -+- Eta1 | |
788 | // | | +- Eta2 | |
789 | // ... ... ... | |
790 | // | | +- EtaM | |
791 | // | +- Centrality2 -+- Eta1 | |
792 | // ... ... ... | |
793 | // | | +- EtaM | |
794 | // ... ... | |
795 | // | +- CentralityN -+- Eta1 | |
796 | // ... ... ... | |
797 | // | +- EtaM | |
798 | // -+- Ring2 -+- Centrality1 -+- Eta1 | |
799 | // | | +- Eta2 | |
800 | // ... ... ... | |
801 | // | | +- EtaM | |
802 | // | +- Centrality2 -+- Eta1 | |
803 | // ... ... ... | |
804 | // | | +- EtaM | |
805 | // ... ... | |
806 | // | +- CentralityN -+- Eta1 | |
807 | // ... ... ... | |
808 | // | +- EtaM | |
809 | // ... ... ... | |
810 | // -+- RingO -+- Centrality1 -+- Eta1 | |
811 | // | +- Eta2 | |
812 | // ... ... | |
813 | // | +- EtaM | |
814 | // +- Centrality2 -+- Eta1 | |
815 | // ... ... | |
816 | // | +- EtaM | |
817 | // ... | |
818 | // +- CentralityN -+- Eta1 | |
819 | // ... ... | |
820 | // +- EtaM | |
821 | // | |
f8715167 | 822 | // fEtaEDists.Expand(eAxis.GetNbins()); |
823 | for (Int_t i = 1; i <= eAxis.GetNbins(); i++) { | |
824 | Double_t min = eAxis.GetBinLowEdge(i); | |
825 | Double_t max = eAxis.GetBinUpEdge(i); | |
5e4d905e | 826 | // Or may we should do it here? In that case we'd have the |
827 | // following structure: | |
828 | // Ring1 -+- Eta1 -+- Centrality1 | |
829 | // | +- Centrality2 | |
830 | // ... ... | |
831 | // | +- CentralityN | |
832 | // +- Eta2 -+- Centrality1 | |
833 | // | +- Centrality2 | |
834 | // ... ... | |
835 | // | +- CentralityN | |
836 | // ... | |
837 | // +- EtaM -+- Centrality1 | |
838 | // +- Centrality2 | |
839 | // ... | |
840 | // +- CentralityN | |
f8715167 | 841 | Make(i, min, max, maxDE, nDEbins, useIncrBin); |
842 | } | |
843 | fList->Add(&fEtaEDists); | |
844 | } | |
845 | //____________________________________________________________________ | |
846 | TObjArray* | |
0bd4b00f | 847 | AliFMDEnergyFitter::RingHistos::Fit(TList* dir, |
848 | const TAxis& eta, | |
849 | Double_t lowCut, | |
850 | UShort_t nParticles, | |
851 | UShort_t minEntries, | |
852 | UShort_t minusBins, | |
853 | Double_t relErrorCut, | |
854 | Double_t chi2nuCut) const | |
f8715167 | 855 | { |
7984e5f7 | 856 | // |
857 | // Fit each histogram to up to @a nParticles particle responses. | |
858 | // | |
859 | // Parameters: | |
860 | // dir Output list | |
861 | // eta Eta axis | |
862 | // lowCut Lower cut | |
863 | // nParticles Max number of convolved landaus to fit | |
864 | // minEntries Minimum number of entries | |
865 | // minusBins Number of bins from peak to subtract to | |
866 | // get the fit range | |
867 | // relErrorCut Cut applied to relative error of parameter. | |
868 | // Note, for multi-particle weights, the cut | |
869 | // is loosend by a factor of 2 | |
870 | // chi2nuCut Cut on @f$ \chi^2/\nu@f$ - | |
871 | // the reduced @f$\chi^2@f$ | |
872 | // | |
873 | ||
c389303e | 874 | // Get our ring list from the output container |
f8715167 | 875 | TList* l = GetOutputList(dir); |
876 | if (!l) return 0; | |
877 | ||
c389303e | 878 | // Get the energy distributions from the output container |
f8715167 | 879 | TList* dists = static_cast<TList*>(l->FindObject("EDists")); |
880 | if (!dists) { | |
881 | AliWarning(Form("Didn't find %s_EtaEDists in %s", | |
882 | fName.Data(), l->GetName())); | |
883 | l->ls(); | |
884 | return 0; | |
885 | } | |
886 | ||
c389303e | 887 | // Container of the fit results histograms |
888 | TObjArray* pars = new TObjArray(3+nParticles+1); | |
f8715167 | 889 | pars->SetName("FitResults"); |
890 | l->Add(pars); | |
891 | ||
c389303e | 892 | // Result objects stored in separate list on the output |
893 | TH1* hChi2 = 0; | |
894 | TH1* hC = 0; | |
895 | TH1* hDelta = 0; | |
896 | TH1* hXi = 0; | |
897 | TH1* hSigma = 0; | |
898 | TH1* hSigmaN = 0; | |
899 | TH1* hN = 0; | |
900 | TH1* hA[nParticles-1]; | |
901 | pars->Add(hChi2 = MakePar("chi2", "#chi^{2}/#nu", eta)); | |
902 | pars->Add(hC = MakePar("c", "Constant", eta)); | |
903 | pars->Add(hDelta = MakePar("delta", "#Delta_{p}", eta)); | |
904 | pars->Add(hXi = MakePar("xi", "#xi", eta)); | |
905 | pars->Add(hSigma = MakePar("sigma", "#sigma", eta)); | |
906 | pars->Add(hSigmaN = MakePar("sigman", "#sigma_{n}", eta)); | |
907 | pars->Add(hN = MakePar("n", "N", eta)); | |
908 | for (UShort_t i = 1; i < nParticles; i++) | |
f8715167 | 909 | pars->Add(hA[i-1] = MakePar(Form("a%d",i+1), Form("a_{%d}",i+1), eta)); |
910 | ||
911 | ||
912 | Int_t nDists = dists->GetEntries(); | |
913 | Int_t low = nDists; | |
914 | Int_t high = 0; | |
915 | for (Int_t i = 0; i < nDists; i++) { | |
916 | TH1D* dist = static_cast<TH1D*>(dists->At(i)); | |
c389303e | 917 | // Ignore empty histograms altoghether |
918 | if (!dist || dist->GetEntries() <= 0) continue; | |
f8715167 | 919 | |
c389303e | 920 | // Scale to the bin-width |
921 | dist->Scale(1., "width"); | |
922 | ||
923 | // Normalize peak to 1 | |
924 | Double_t max = dist->GetMaximum(); | |
0bd4b00f | 925 | if (max <= 0) continue; |
c389303e | 926 | dist->Scale(1/max); |
927 | ||
928 | // Check that we have enough entries | |
0bd4b00f | 929 | if (dist->GetEntries() <= minEntries) { |
930 | AliWarning(Form("Histogram at %3d (%s) has too few entries (%d <= %d)", | |
931 | i, dist->GetName(), Int_t(dist->GetEntries()), | |
932 | minEntries)); | |
933 | continue; | |
934 | } | |
f8715167 | 935 | |
c389303e | 936 | // Now fit |
937 | TF1* res = FitHist(dist,lowCut,nParticles,minusBins, | |
938 | relErrorCut,chi2nuCut); | |
f8715167 | 939 | if (!res) continue; |
c389303e | 940 | // dist->GetListOfFunctions()->Add(res); |
0bd4b00f | 941 | |
c389303e | 942 | // Store eta limits |
f8715167 | 943 | low = TMath::Min(low,i+1); |
944 | high = TMath::Max(high,i+1); | |
945 | ||
c389303e | 946 | // Get the reduced chi square |
f8715167 | 947 | Double_t chi2 = res->GetChisquare(); |
948 | Int_t ndf = res->GetNDF(); | |
c389303e | 949 | |
950 | // Store results of best fit in output histograms | |
951 | res->SetLineWidth(4); | |
952 | hChi2 ->SetBinContent(i+1, ndf > 0 ? chi2 / ndf : 0); | |
953 | hC ->SetBinContent(i+1, res->GetParameter(kC)); | |
954 | hDelta ->SetBinContent(i+1, res->GetParameter(kDelta)); | |
955 | hXi ->SetBinContent(i+1, res->GetParameter(kXi)); | |
956 | hSigma ->SetBinContent(i+1, res->GetParameter(kSigma)); | |
957 | hSigmaN ->SetBinContent(i+1, res->GetParameter(kSigmaN)); | |
958 | hN ->SetBinContent(i+1, res->GetParameter(kN)); | |
959 | ||
960 | hC ->SetBinError(i+1, res->GetParError(kC)); | |
961 | hDelta ->SetBinError(i+1, res->GetParError(kDelta)); | |
962 | hXi ->SetBinError(i+1, res->GetParError(kXi)); | |
963 | hSigma ->SetBinError(i+1, res->GetParError(kSigma)); | |
964 | hSigmaN->SetBinError(i+1, res->GetParError(kSigmaN)); | |
965 | hN ->SetBinError(i+1, res->GetParError(kN)); | |
966 | ||
967 | for (UShort_t j = 0; j < nParticles-1; j++) { | |
968 | hA[j]->SetBinContent(i+1, res->GetParameter(kA+j)); | |
969 | hA[j]->SetBinError(i+1, res->GetParError(kA+j)); | |
f8715167 | 970 | } |
971 | } | |
972 | ||
c389303e | 973 | // Fit the full-ring histogram |
f8715167 | 974 | TH1* total = GetOutputHist(l, Form("%s_edist", fName.Data())); |
4b9857f3 | 975 | if (total && total->GetEntries() >= minEntries) { |
0bd4b00f | 976 | |
977 | // Scale to the bin-width | |
978 | total->Scale(1., "width"); | |
979 | ||
980 | // Normalize peak to 1 | |
981 | Double_t max = total->GetMaximum(); | |
982 | if (max > 0) total->Scale(1/max); | |
983 | ||
c389303e | 984 | TF1* res = FitHist(total,lowCut,nParticles,minusBins, |
985 | relErrorCut,chi2nuCut); | |
f8715167 | 986 | if (res) { |
c389303e | 987 | // Make histograms for the result of this fit |
f8715167 | 988 | Double_t chi2 = res->GetChisquare(); |
989 | Int_t ndf = res->GetNDF(); | |
c389303e | 990 | pars->Add(MakeTotal("t_chi2", "#chi^{2}/#nu", eta, low, high, |
f8715167 | 991 | ndf > 0 ? chi2/ndf : 0, 0)); |
c389303e | 992 | pars->Add(MakeTotal("t_c", "Constant", eta, low, high, |
993 | res->GetParameter(kC), | |
994 | res->GetParError(kC))); | |
995 | pars->Add(MakeTotal("t_delta", "#Delta_{p}", eta, low, high, | |
996 | res->GetParameter(kDelta), | |
997 | res->GetParError(kDelta))); | |
998 | pars->Add(MakeTotal("t_xi", "#xi", eta, low, high, | |
999 | res->GetParameter(kXi), | |
1000 | res->GetParError(kXi))); | |
1001 | pars->Add(MakeTotal("t_sigma", "#sigma", eta, low, high, | |
1002 | res->GetParameter(kSigma), | |
1003 | res->GetParError(kSigma))); | |
1004 | pars->Add(MakeTotal("t_sigman", "#sigma_{n}", eta, low, high, | |
1005 | res->GetParameter(kSigmaN), | |
1006 | res->GetParError(kSigmaN))); | |
1007 | pars->Add(MakeTotal("t_n", "N", eta, low, high, | |
1008 | res->GetParameter(kN),0)); | |
1009 | for (UShort_t j = 0; j < nParticles-1; j++) | |
1010 | pars->Add(MakeTotal(Form("t_a%d",j+2), | |
1011 | Form("a_{%d}",j+2), eta, low, high, | |
1012 | res->GetParameter(kA+j), | |
1013 | res->GetParError(kA+j))); | |
f8715167 | 1014 | } |
1015 | } | |
1016 | ||
c389303e | 1017 | // Clean up list of histogram. Histograms with no entries or |
1018 | // no functions are deleted. We have to do this using the TObjLink | |
1019 | // objects stored in the list since ROOT cannot guaranty the validity | |
1020 | // of iterators when removing from a list - tsck. Should just implement | |
1021 | // TIter::Remove(). | |
f8715167 | 1022 | TObjLink* lnk = dists->FirstLink(); |
1023 | while (lnk) { | |
1024 | TH1* h = static_cast<TH1*>(lnk->GetObject()); | |
0bd4b00f | 1025 | bool remove = false; |
1026 | if (h->GetEntries() <= 0) { | |
1027 | // AliWarning(Form("No entries in %s - removing", h->GetName())); | |
1028 | remove = true; | |
1029 | } | |
1030 | else if (h->GetListOfFunctions()->GetEntries() <= 0) { | |
1031 | // AliWarning(Form("No fuctions associated with %s - removing", | |
1032 | // h->GetName())); | |
1033 | remove = true; | |
1034 | } | |
1035 | if (remove) { | |
f8715167 | 1036 | TObjLink* keep = lnk->Next(); |
1037 | dists->Remove(lnk); | |
1038 | lnk = keep; | |
1039 | continue; | |
1040 | } | |
1041 | lnk = lnk->Next(); | |
1042 | } | |
1043 | ||
1044 | return pars; | |
1045 | } | |
1046 | ||
1047 | //____________________________________________________________________ | |
1048 | TF1* | |
4b9857f3 | 1049 | AliFMDEnergyFitter::RingHistos::FitHist(TH1* dist, |
1050 | Double_t lowCut, | |
c389303e | 1051 | UShort_t nParticles, |
1052 | UShort_t minusBins, | |
1053 | Double_t relErrorCut, | |
1054 | Double_t chi2nuCut) const | |
f8715167 | 1055 | { |
7984e5f7 | 1056 | // |
1057 | // Fit a signal histogram. First, the bin @f$ b_{min}@f$ with | |
1058 | // maximum bin content in the range @f$ [E_{min},\infty]@f$ is | |
1059 | // found. Then the fit range is set to the bin range | |
1060 | // @f$ [b_{min}-\Delta b,b_{min}+2\Delta b]@f$, and a 1 | |
1061 | // particle signal is fitted to that. The parameters of that fit | |
1062 | // is then used as seeds for a fit of the @f$ N@f$ particle response | |
1063 | // to the data in the range | |
1064 | // @f$ [b_{min}-\Delta b,N(\Delta_1+\xi_1\log(N))+2N\xi@f$ | |
1065 | // | |
1066 | // Parameters: | |
1067 | // dist Histogram to fit | |
1068 | // lowCut Lower cut @f$ E_{min}@f$ on signal | |
1069 | // nParticles Max number @f$ N@f$ of convolved landaus to fit | |
1070 | // minusBins Number of bins @f$ \Delta b@f$ from peak to | |
1071 | // subtract to get the fit range | |
1072 | // relErrorCut Cut applied to relative error of parameter. | |
1073 | // Note, for multi-particle weights, the cut | |
1074 | // is loosend by a factor of 2 | |
1075 | // chi2nuCut Cut on @f$ \chi^2/\nu@f$ - | |
1076 | // the reduced @f$\chi^2@f$ | |
1077 | // | |
1078 | // Return: | |
1079 | // The best fit function | |
1080 | // | |
f8715167 | 1081 | Double_t maxRange = 10; |
1082 | ||
c389303e | 1083 | // Create a fitter object |
4b9857f3 | 1084 | AliForwardUtil::ELossFitter f(lowCut, maxRange, minusBins); |
1085 | f.Clear(); | |
f8715167 | 1086 | |
c389303e | 1087 | |
4b9857f3 | 1088 | // If we are only asked to fit a single particle, return this fit, |
1089 | // no matter what. | |
c389303e | 1090 | if (nParticles == 1) { |
4b9857f3 | 1091 | TF1* r = f.Fit1Particle(dist, 0); |
1092 | if (!r) return 0; | |
1093 | return new TF1(*r); | |
f8715167 | 1094 | } |
f8715167 | 1095 | |
4b9857f3 | 1096 | // Fit from 2 upto n particles |
c389303e | 1097 | for (Int_t i = 2; i <= nParticles; i++) f.FitNParticle(dist, i, 0); |
f8715167 | 1098 | |
f8715167 | 1099 | |
4b9857f3 | 1100 | // Now, we need to select the best fit |
fb3430ac | 1101 | Int_t nFits = f.GetFitResults().GetEntriesFast(); |
4b9857f3 | 1102 | TF1* good[nFits]; |
1103 | for (Int_t i = nFits-1; i >= 0; i--) { | |
c389303e | 1104 | good[i] = 0; |
fb3430ac | 1105 | TF1* ff = static_cast<TF1*>(f.GetFunctions().At(i)); |
c389303e | 1106 | // ff->SetLineColor(Color()); |
1107 | ff->SetRange(0, maxRange); | |
1108 | dist->GetListOfFunctions()->Add(new TF1(*ff)); | |
fb3430ac | 1109 | if (CheckResult(static_cast<TFitResult*>(f.GetFitResults().At(i)), |
c389303e | 1110 | relErrorCut, chi2nuCut)) { |
1111 | good[i] = ff; | |
1112 | ff->SetLineWidth(2); | |
1113 | // f.fFitResults.At(i)->Print("V"); | |
1114 | } | |
4b9857f3 | 1115 | } |
1116 | // If all else fails, use the 1 particle fit | |
fb3430ac | 1117 | TF1* ret = static_cast<TF1*>(f.GetFunctions().At(0)); |
c389303e | 1118 | |
1119 | // Find the fit with the most valid particles | |
4b9857f3 | 1120 | for (Int_t i = nFits-1; i > 0; i--) { |
1121 | if (!good[i]) continue; | |
c389303e | 1122 | if (fDebug > 1) { |
1123 | AliInfo(Form("Choosing fit with n=%d", i+1)); | |
fb3430ac | 1124 | f.GetFitResults().At(i)->Print(); |
c389303e | 1125 | } |
4b9857f3 | 1126 | ret = good[i]; |
f8715167 | 1127 | break; |
1128 | } | |
c389303e | 1129 | // Give a warning if we're using fall-back |
fb3430ac | 1130 | if (ret == f.GetFunctions().At(0)) { |
c389303e | 1131 | AliWarning("Choosing fall-back 1 particle fit"); |
0bd4b00f | 1132 | } |
c389303e | 1133 | // Copy our result and return (the functions are owned by the fitter) |
1134 | TF1* fret = new TF1(*ret); | |
1135 | return fret; | |
f8715167 | 1136 | } |
1137 | ||
1138 | //____________________________________________________________________ | |
1139 | Bool_t | |
c389303e | 1140 | AliFMDEnergyFitter::RingHistos::CheckResult(TFitResult* r, |
1141 | Double_t relErrorCut, | |
1142 | Double_t chi2nuCut) const | |
f8715167 | 1143 | { |
7984e5f7 | 1144 | // |
1145 | // Check the result of the fit. Returns true if | |
1146 | // - @f$ \chi^2/\nu < \max{\chi^2/\nu}@f$ | |
1147 | // - @f$ \Delta p_i/p_i < \delta_e@f$ for all parameters. Note, | |
1148 | // for multi-particle fits, this requirement is relaxed by a | |
1149 | // factor of 2 | |
1150 | // - @f$ a_{n} > 10^{-7}@f$ when fitting to an @f$ n@f$ | |
1151 | // particle response | |
1152 | // | |
1153 | // Parameters: | |
1154 | // r Result to check | |
1155 | // relErrorCut Cut @f$ \delta_e@f$ applied to relative error | |
1156 | // of parameter. | |
1157 | // chi2nuCut Cut @f$ \max{\chi^2/\nu}@f$ | |
1158 | // | |
1159 | // Return: | |
1160 | // true if fit is good. | |
1161 | // | |
c389303e | 1162 | if (fDebug > 10) r->Print(); |
1163 | TString n = r->GetName(); | |
1164 | n.ReplaceAll("TFitResult-", ""); | |
4b9857f3 | 1165 | Double_t chi2 = r->Chi2(); |
1166 | Int_t ndf = r->Ndf(); | |
f8715167 | 1167 | // Double_t prob = r.Prob(); |
c389303e | 1168 | Bool_t ret = kTRUE; |
1169 | ||
1170 | // Check that the reduced chi square isn't larger than 5 | |
1171 | if (ndf <= 0 || chi2 / ndf > chi2nuCut) { | |
0bd4b00f | 1172 | if (fDebug > 2) { |
c389303e | 1173 | AliWarning(Form("%s: chi^2/ndf=%12.5f/%3d=%12.5f>%12.5f", |
1174 | n.Data(), chi2, ndf, (ndf<0 ? 0 : chi2/ndf), | |
0bd4b00f | 1175 | chi2nuCut)); } |
c389303e | 1176 | ret = kFALSE; |
f8715167 | 1177 | } |
1178 | ||
c389303e | 1179 | // Check each parameter |
4b9857f3 | 1180 | UShort_t nPar = r->NPar(); |
f8715167 | 1181 | for (UShort_t i = 0; i < nPar; i++) { |
c389303e | 1182 | if (i == kN) continue; // Skip the number parameter |
f8715167 | 1183 | |
c389303e | 1184 | // Get value and error and check value |
1185 | Double_t v = r->Parameter(i); | |
1186 | Double_t e = r->ParError(i); | |
f8715167 | 1187 | if (v == 0) continue; |
c389303e | 1188 | |
1189 | // Calculate the relative error and check it | |
1190 | Double_t re = e / v; | |
1191 | Double_t cut = relErrorCut * (i < kN ? 1 : 2); | |
1192 | if (re > cut) { | |
0bd4b00f | 1193 | if (fDebug > 2) { |
c389303e | 1194 | AliWarning(Form("%s: Delta %s/%s=%9.5f/%9.5f=%5.1f%%>%5.1f%%", |
1195 | n.Data(), r->ParName(i).c_str(), | |
1196 | r->ParName(i).c_str(), e, v, | |
1197 | 100*(v == 0 ? 0 : e/v), | |
0bd4b00f | 1198 | 100*(cut))); } |
c389303e | 1199 | ret = kFALSE; |
f8715167 | 1200 | } |
1201 | } | |
c389303e | 1202 | |
1203 | // Check if we have scale parameters | |
1204 | if (nPar > kN) { | |
1205 | ||
1206 | // Check that the last particle has a significant contribution | |
4b9857f3 | 1207 | Double_t lastScale = r->Parameter(nPar-1); |
1208 | if (lastScale <= 1e-7) { | |
0bd4b00f | 1209 | if (fDebug) { |
c389303e | 1210 | AliWarning(Form("%s: %s=%9.6f<1e-7", |
0bd4b00f | 1211 | n.Data(), r->ParName(nPar-1).c_str(), lastScale)); } |
c389303e | 1212 | ret = kFALSE; |
f8715167 | 1213 | } |
1214 | } | |
c389303e | 1215 | return ret; |
f8715167 | 1216 | } |
1217 | ||
1218 | ||
0bd4b00f | 1219 | //__________________________________________________________________ |
1220 | void | |
fb3430ac | 1221 | AliFMDEnergyFitter::RingHistos::FindBestFits(const TList* d, |
0bd4b00f | 1222 | AliFMDCorrELossFit& obj, |
1223 | const TAxis& eta, | |
1224 | Double_t relErrorCut, | |
1225 | Double_t chi2nuCut, | |
1226 | Double_t minWeightCut) | |
1227 | { | |
7984e5f7 | 1228 | // |
1229 | // Find the best fits | |
1230 | // | |
1231 | // Parameters: | |
1232 | // d Parent list | |
1233 | // obj Object to add fits to | |
1234 | // eta Eta axis | |
1235 | // relErrorCut Cut applied to relative error of parameter. | |
1236 | // Note, for multi-particle weights, the cut | |
1237 | // is loosend by a factor of 2 | |
1238 | // chi2nuCut Cut on @f$ \chi^2/\nu@f$ - | |
1239 | // the reduced @f$\chi^2@f$ | |
1240 | // minWeightCut Least valid @f$ a_i@f$ | |
1241 | // | |
1242 | ||
0bd4b00f | 1243 | // Get our ring list from the output container |
1244 | TList* l = GetOutputList(d); | |
1245 | if (!l) return; | |
1246 | ||
1247 | // Get the energy distributions from the output container | |
1248 | TList* dists = static_cast<TList*>(l->FindObject("EDists")); | |
1249 | if (!dists) { | |
1250 | AliWarning(Form("Didn't find %s_EtaEDists in %s", | |
1251 | fName.Data(), l->GetName())); | |
1252 | l->ls(); | |
1253 | return; | |
1254 | } | |
1255 | Int_t nBin = eta.GetNbins(); | |
1256 | ||
1257 | for (Int_t b = 1; b <= nBin; b++) { | |
1258 | TString n(Form(fgkEDistFormat, fName.Data(), b)); | |
1259 | TH1D* dist = static_cast<TH1D*>(dists->FindObject(n)); | |
1260 | // Ignore empty histograms altoghether | |
1261 | if (!dist || dist->GetEntries() <= 0) continue; | |
1262 | ||
1263 | AliFMDCorrELossFit::ELossFit* best = FindBestFit(dist, | |
1264 | relErrorCut, | |
1265 | chi2nuCut, | |
1266 | minWeightCut); | |
1267 | best->fDet = fDet; | |
1268 | best->fRing = fRing; | |
1269 | best->fBin = b; // | |
1270 | // Double_t eta = fAxis->GetBinCenter(b); | |
1271 | obj.SetFit(fDet, fRing, b, new AliFMDCorrELossFit::ELossFit(*best)); | |
1272 | } | |
1273 | } | |
1274 | ||
1275 | //__________________________________________________________________ | |
1276 | AliFMDCorrELossFit::ELossFit* | |
fb3430ac | 1277 | AliFMDEnergyFitter::RingHistos::FindBestFit(const TH1* dist, |
0bd4b00f | 1278 | Double_t relErrorCut, |
1279 | Double_t chi2nuCut, | |
1280 | Double_t minWeightCut) | |
1281 | { | |
7984e5f7 | 1282 | // |
1283 | // Find the best fit | |
1284 | // | |
1285 | // Parameters: | |
1286 | // dist Histogram | |
1287 | // relErrorCut Cut applied to relative error of parameter. | |
1288 | // Note, for multi-particle weights, the cut | |
1289 | // is loosend by a factor of 2 | |
1290 | // chi2nuCut Cut on @f$ \chi^2/\nu@f$ - | |
1291 | // the reduced @f$\chi^2@f$ | |
1292 | // minWeightCut Least valid @f$ a_i@f$ | |
1293 | // | |
1294 | // Return: | |
1295 | // Best fit | |
1296 | // | |
0bd4b00f | 1297 | TList* funcs = dist->GetListOfFunctions(); |
1298 | TIter next(funcs); | |
1299 | TF1* func = 0; | |
1300 | fFits.Clear(); | |
1301 | Int_t i = 0; | |
1302 | // Info("FindBestFit", "%s", dist->GetName()); | |
1303 | while ((func = static_cast<TF1*>(next()))) { | |
1304 | AliFMDCorrELossFit::ELossFit* fit = | |
1305 | new(fFits[i++]) AliFMDCorrELossFit::ELossFit(0,*func); | |
1306 | fit->CalculateQuality(chi2nuCut, relErrorCut, minWeightCut); | |
1307 | } | |
1308 | fFits.Sort(false); | |
1309 | // fFits.Print(); | |
1310 | return static_cast<AliFMDCorrELossFit::ELossFit*>(fFits.At(0)); | |
1311 | } | |
1312 | ||
1313 | ||
f8715167 | 1314 | //____________________________________________________________________ |
1315 | void | |
1316 | AliFMDEnergyFitter::RingHistos::Output(TList* dir) | |
1317 | { | |
7984e5f7 | 1318 | // |
1319 | // Define outputs | |
1320 | // | |
1321 | // Parameters: | |
1322 | // dir | |
1323 | // | |
f8715167 | 1324 | fList = DefineOutputList(dir); |
1325 | } | |
1326 | ||
1327 | //____________________________________________________________________ | |
1328 | // | |
1329 | // EOF | |
1330 | // |