]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWGLF/FORWARD/analysis2/AliLandauGausFitter.h
Merge branch 'feature-movesplit'
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / AliLandauGausFitter.h
CommitLineData
59eb7e1a 1#ifndef ALILANDAUGAUSFITTER_H
2#define ALILANDAUGAUSFITTER_H
3/**
4 * @file AliLandauGausFitter.h
5 * @author Christian Holm Christensen <cholm@nbi.dk>
6 * @date Tue Mar 11 08:56:03 2014
7 *
8 * @brief Declaration and implementation of fitter of Landau-Gauss
9 * distributions to energy loss spectra.
10 *
11 * @ingroup pwglf_forward
12 */
13#include <AliLandauGaus.h>
14#include <TH1.h>
15#include <TF1.h>
16#include <TMath.h>
17#include <TObjArray.h>
18#include <TString.h>
19#include <TArray.h>
20#include <TFitResult.h>
21#include <TError.h>
22
23/**
24 * Fit Landau-Gauss distributions to energy loss distributions
25 *
26 * @see AliLandauGaus
27 *
28 * @ingroup pwglf_forward
29 */
30class AliLandauGausFitter
31{
32public:
33 /**
34 * Enumeration of parameters
35 */
36 enum {
37 /** Index of pre-constant @f$ C@f$ */
38 kC = AliLandauGaus::kC,
39 /** Index of most probable value @f$ \Delta_p@f$ */
40 kDelta = AliLandauGaus::kDelta,
41 /** Index of Landau width @f$ \xi@f$ */
42 kXi = AliLandauGaus::kXi,
43 /** Index of Gaussian width @f$ \sigma@f$ */
44 kSigma = AliLandauGaus::kSigma,
45 /** Index of Gaussian additional width @f$ \sigma_n@f$ */
46 kSigmaN = AliLandauGaus::kSigmaN,
47 /** Index of Number of particles @f$ N@f$ */
48 kN = AliLandauGaus::kN,
49 /** Base index of particle strengths @f$ a_i@f$ for
50 @f$i=2,\ldots,N@f$ */
51 kA = AliLandauGaus::kA
52 };
53 /**
54 * Get the fit options to use
55 *
56 * @return Fit options used through-out
57 */
58 static const char* GetFitOptions() { return "RNS"; }
59 /**
60 * Constructor
61 *
62 * @param lowCut Lower cut of spectrum - data below this cuts is ignored
63 * @param maxRange Maximum range to fit to
64 * @param minusBins The number of bins below maximum to use
65 */
66 AliLandauGausFitter(Double_t lowCut, Double_t maxRange, UShort_t minusBins)
67 : fLowCut(lowCut), fMaxRange(maxRange), fMinusBins(minusBins),
68 fFitResults(0), fFunctions(0), fDebug(false)
69 {
70 fFitResults.SetOwner();
71 fFunctions.SetOwner();
72 }
73 /**
74 * Destructor
75 *
76 */
77 virtual ~AliLandauGausFitter()
78 {
79 fFitResults.Delete();
80 fFunctions.Delete();
81 }
82 /**
83 * Enable/disable debugging output.
84 *
85 * @param debug If true, enable debugging output
86 */
87 void SetDebug(Bool_t debug=true) { fDebug = debug; }
88 /**
89 * Clear internal arrays
90 *
91 */
92 void Clear()
93 {
94 fFitResults.Clear();
95 fFunctions.Clear();
96 }
97 /**
98 * Fit a 1-particle signal to the passed energy loss distribution
99 *
100 * Note that this function clears the internal arrays first
101 *
102 * @param dist Data to fit the function to
103 * @param sigman If larger than zero, the initial guess of the
104 * detector induced noise. If zero or less, then this
105 * parameter is ignored in the fit (fixed at 0)
106 *
107 * @return The function fitted to the data
108 */
109 TF1* Fit1Particle(TH1* dist, Double_t sigman=-1);
110 /**
111 * Fit a N-particle signal to the passed energy loss distribution
112 *
113 * If there's no 1-particle fit present, it does that first
114 *
115 * @param dist Data to fit the function to
116 * @param n Number of particle signals to fit
117 * @param sigman If larger than zero, the initial guess of the
118 * detector induced noise. If zero or less, then this
119 * parameter is ignored in the fit (fixed at 0)
120 *
121 * @return The function fitted to the data
122 */
123 TF1* FitNParticle(TH1* dist, UShort_t n, Double_t sigman=-1);
124 /**
125 * Fit a composite distribution of energy loss from both primaries
126 * and secondaries
127 *
128 * @param dist Distribution
129 * @param sigman If larger than zero, the initial guess of the
130 * detector included noise. If zero or less this
131 * parameter is fixed to 0.
132 *
133 * @return Function fitted to the data
134 */
135 TF1* FitComposite(TH1* dist, Double_t sigman);
136 /**
137 * Get Lower cut on data
138 *
139 * @return Lower cut on data
140 */
141 Double_t GetLowCut() const { return fLowCut; }
142 /**
143 * Get Maximum range to fit
144 *
145 * @return Maximum range to fit
146 */
147 Double_t GetMaxRange() const { return fMaxRange; }
148 /**
149 * Get Number of bins from maximum to fit 1st peak
150 *
151 * @return Number of bins from maximum to fit 1st peak
152 */
153 UShort_t GetMinusBins() const { return fMinusBins; }
154 /**
155 * Get Array of fit results
156 *
157 * @return Array of fit results
158 */
159 const TObjArray& GetFitResults() const { return fFitResults; }
160 /**
161 * Get Array of fit results
162 *
163 * @return Array of fit results
164 */
165 TObjArray& GetFitResults() { return fFitResults; }
166 /**
167 * Get Array of functions
168 *
169 * @return Array of functions
170 */
171 const TObjArray& GetFunctions() const { return fFunctions; }
172 /**
173 * Get Array of functions
174 *
175 * @return Array of functions
176 */
177 TObjArray& GetFunctions() { return fFunctions; }
178protected:
179 /**
180 * Set parameter limits on the function @a f. The limits are only
181 * set if @f$ low \le test \le high@f$
182 *
183 * @param f Function object
184 * @param iPar Parameter number
185 * @param test Initial guess
186 * @param low Low limit
187 * @param high high limit
188 */
189 void SetParLimits(TF1* f, Int_t iPar, Double_t test,
190 Double_t low, Double_t high)
191 {
192 if (test < low || test > high) {
193 ::Warning("","Initial value of %s=%f not in [%f,%f]",
194 f->GetParName(iPar), test, low, high);
195 return;
196 }
197 if (fDebug)
198 ::Info(/*"SetParLimits"*/"", "Set par limits on %-12s=%f: [%f,%f]",
199 f->GetParName(iPar), test, low, high);
200 f->SetParLimits(iPar, low, high);
201 }
202 const Double_t fLowCut; // Lower cut on data
203 const Double_t fMaxRange; // Maximum range to fit
204 const UShort_t fMinusBins; // Number of bins from maximum to fit 1st peak
205 TObjArray fFitResults; // Array of fit results
206 TObjArray fFunctions; // Array of functions
207 Bool_t fDebug; // Debug flag
208};
209
210
211//____________________________________________________________________
212inline TF1*
213AliLandauGausFitter::Fit1Particle(TH1* dist, Double_t sigman)
214{
215 // Clear the cache
216 Clear();
217
218 // Find the fit range
219 Int_t cutBin = TMath::Max(dist->GetXaxis()->FindBin(fLowCut),3);
220 Int_t maxBin = TMath::Min(dist->GetXaxis()->FindBin(fMaxRange),
221 dist->GetNbinsX());
222 dist->GetXaxis()->SetRange(cutBin, maxBin);
223 // dist->GetXaxis()->SetRangeUser(fLowCut, fMaxRange);
224
225 // Get the bin with maximum
226 Int_t peakBin = dist->GetMaximumBin();
227 Double_t peakE = dist->GetBinLowEdge(peakBin);
228 Double_t rmsE = dist->GetRMS();
229
230 // Get the low edge
231 // dist->GetXaxis()->SetRangeUser(fLowCut, peakE);
232 Int_t minBin = peakBin - fMinusBins; // dist->GetMinimumBin();
233 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
234 Double_t maxE = dist->GetBinCenter(peakBin+2*fMinusBins);
235
236 Int_t minEb = dist->GetXaxis()->FindBin(minE);
237 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
238 Double_t intg = dist->Integral(minEb, maxEb);
239 if (intg <= 0) {
240 ::Warning("Fit1Particle",
241 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
242 dist->GetName(), minE, maxE, minEb, maxEb, intg);
243 return 0;
244 }
245
246 // Restore the range
247 dist->GetXaxis()->SetRange(1, maxBin);
248
249 // Define the function to fit
250 TF1* f = AliLandauGaus::MakeF1(intg,peakE,peakE/10,peakE/5,sigman,minE,maxE);
251 SetParLimits(f, kDelta, peakE, minE, fMaxRange);
252 SetParLimits(f, kXi, peakE, 0, rmsE); // 0.1
253 SetParLimits(f, kSigma, peakE/5, 1e-5, rmsE); // 0.1
254 if (sigman <= 0)
255 f->FixParameter(kSigmaN, 0);
256 else
257 SetParLimits(f, kSigmaN, peakE, 0, rmsE);
258
259
260 TString opts(Form("%s%s", GetFitOptions(), fDebug ? "" : "Q"));
261 // Do the fit, getting the result object
262 if (fDebug)
263 ::Info(/*"Fit1Particle"*/"", "Fitting in the range %f,%f", minE, maxE);
264 TFitResultPtr r = dist->Fit(f, opts, "", minE, maxE);
265 if (!r.Get()) {
266 ::Warning("Fit1Particle",
267 "No fit returned when processing %s in the range [%f,%f] "
268 "options %s", dist->GetName(), minE, maxE, opts.Data());
269 return 0;
270 }
271 // f->SetRange(minE, fMaxRange);
272 fFitResults.AddAtAndExpand(new TFitResult(*r), 0);
273 fFunctions.AddAtAndExpand(f, 0);
274
275 return f;
276}
277//____________________________________________________________________
278inline TF1*
279AliLandauGausFitter::FitNParticle(TH1* dist, UShort_t n, Double_t sigman)
280{
281 // Get the seed fit result
282 TFitResult* r = static_cast<TFitResult*>(fFitResults.At(0));
283 TF1* f = static_cast<TF1*>(fFunctions.At(0));
284 if (!r || !f) {
285 f = Fit1Particle(dist, sigman);
286 r = static_cast<TFitResult*>(fFitResults.At(0));
287 if (!r || !f) {
288 ::Warning("FitNLandau", "No first shot at landau fit");
289 return 0;
290 }
291 }
292
293 // Get some parameters from seed fit
294 Double_t delta1 = r->Parameter(kDelta);
295 Double_t xi1 = r->Parameter(kXi);
296 Double_t maxEi = n * (delta1 + xi1 * TMath::Log(n)) + 2 * n * xi1;
297 Double_t minE = f->GetXmin();
298
299 Int_t minEb = dist->GetXaxis()->FindBin(minE);
300 Int_t maxEb = dist->GetXaxis()->FindBin(maxEi);
301 Double_t rmsE = dist->GetRMS();
302 Double_t intg = dist->Integral(minEb, maxEb);
303 if (intg <= 0) {
304 ::Warning("FitNParticle",
305 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
306 dist->GetName(), minE, maxEi, minEb, maxEb, intg);
307 return 0;
308 }
309
310 // Array of weights
311 TArrayD a(n-1);
312 for (UShort_t i = 2; i <= n; i++)
313 a.fArray[i-2] = (n == 2 ? 0.05 : 0.000001);
314 // Make the fit function
315 f = AliLandauGaus::MakeFn(r->Parameter(kC),
316 r->Parameter(kDelta),
317 r->Parameter(kXi),
318 r->Parameter(kSigma),
319 r->Parameter(kSigmaN),
320 n, a.fArray, minE, maxEi);
321 SetParLimits(f,kDelta, f->GetParameter(kDelta), minE, fMaxRange);
322 SetParLimits(f,kXi, f->GetParameter(kXi), 0, 2*rmsE); //0.1
323 SetParLimits(f,kSigma, f->GetParameter(kSigma), 1e-5, 2*rmsE); //0.1
324 if (sigman <= 0) f->FixParameter(kSigmaN, 0);
325 else
326 SetParLimits(f,kSigmaN, f->GetParameter(kSigmaN), 0, rmsE);
327
328 // Set the range and name of the scale parameters
329 for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit
330 SetParLimits(f,kA+i-2, a[i-2], 0, 1);
331 }
332
333 // Do the fit
334 TString opts(Form("%s%s", GetFitOptions(), fDebug ? "" : "Q"));
335 if (fDebug)
336 ::Info(/*"FitNParticle"*/"",
337 "Fitting in the range %f,%f (%d)", minE, maxEi, n);
338 TFitResultPtr tr = dist->Fit(f, opts, "", minE, maxEi);
339
340 // f->SetRange(minE, fMaxRange);
341 fFitResults.AddAtAndExpand(new TFitResult(*tr), n-1);
342 fFunctions.AddAtAndExpand(f, n-1);
343
344 return f;
345}
346//____________________________________________________________________
347inline TF1*
348AliLandauGausFitter::FitComposite(TH1* dist, Double_t sigman)
349{
350 // Find the fit range
351 Int_t cutBin = TMath::Max(dist->GetXaxis()->FindBin(fLowCut),3);
352 Int_t maxBin = TMath::Min(dist->GetXaxis()->FindBin(fMaxRange),
353 dist->GetNbinsX());
354 dist->GetXaxis()->SetRange(cutBin, maxBin);
355
356 // Get the bin with maximum
357 Int_t peakBin = dist->GetMaximumBin();
358 Double_t peakE = dist->GetBinLowEdge(peakBin);
359
360 // Get the low edge
361 // dist->GetXaxis()->SetRangeUser(fLowCut, peakE);
362 Int_t minBin = peakBin - fMinusBins; // dist->GetMinimumBin();
363 Double_t minE = TMath::Max(dist->GetBinCenter(minBin),fLowCut);
364 Double_t maxE = dist->GetBinCenter(peakBin+2*fMinusBins);
365
366 // Get the range in bins and the integral of that range
367 Int_t minEb = dist->GetXaxis()->FindBin(minE);
368 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
369 Double_t intg = dist->Integral(minEb, maxEb);
370 if (intg <= 0) {
371 ::Warning("Fit1Particle",
372 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
373 dist->GetName(), minE, maxE, minEb, maxEb, intg);
374 return 0;
375 }
376
377 // Restore the range
378 dist->GetXaxis()->SetRange(1, maxBin);
379
380 // Define the function to fit
381 TF1* seed = AliLandauGaus::MakeF1(1,peakE,peakE/10,peakE/5,sigman,minE,maxE);
382
383 // Set initial guesses, parameter names, and limits
384 seed->SetParLimits(kDelta, minE, fMaxRange);
385 seed->SetParLimits(kXi, 0.00, 0.1);
386 seed->SetParLimits(kSigma, 1e-5, 0.1);
387 if (sigman <= 0) seed->FixParameter(kSigmaN, 0);
388 else seed->SetParLimits(kSigmaN, 0, fMaxRange);
389
390 // Do the fit, getting the result object
391 if (fDebug)
392 ::Info(/*"FitComposite"*/"", "Fitting seed in the range %f,%f", minE, maxE);
393 /* TFitResultPtr r = */ dist->Fit(seed, GetFitOptions(), "", minE, maxE);
394
395 maxE = dist->GetXaxis()->GetXmax();
396 TF1* comp =
397 AliLandauGaus::MakeComposite(0.8 * seed->GetParameter(kC),
398 seed->GetParameter(kDelta),
399 seed->GetParameter(kDelta)/10,
400 seed->GetParameter(kDelta)/5,
401 1.20 * seed->GetParameter(kC),
402 seed->GetParameter(kXi),
403 minE, maxE);
404 // comp->SetParLimits(kC, minE, fMaxRange); // C
405 comp->SetParLimits(kDelta, minE, fMaxRange); // Delta
406 comp->SetParLimits(kXi, 0.00, fMaxRange); // Xi
407 comp->SetParLimits(kSigma, 1e-5, fMaxRange); // Sigma
408 // comp->SetParLimits(kSigma+1, minE, fMaxRange); // C
409 comp->SetParLimits(kSigma+2, 0.00, fMaxRange); // Xi'
410 comp->SetLineColor(kRed+1);
411 comp->SetLineWidth(3);
412
413 // Do the fit, getting the result object
414 TString opts(Form("%s%s", GetFitOptions(), fDebug ? "" : "Q"));
415 if (fDebug)
416 ::Info("FitComposite", "Fitting composite in the range %f,%f", minE, maxE);
417 /* TFitResultPtr r = */ dist->Fit(comp, opts, "", minE, maxE);
418
419#if 0
420 // This is to store the two components with the output
421 TF1* part1 = static_cast<TF1*>(seed->Clone("part1"));
422 part1->SetLineColor(kGreen+1);
423 part1->SetLineWidth(4);
424 part1->SetRange(minE, maxE);
425 part1->SetParameters(comp->GetParameter(0), // C
426 comp->GetParameter(1), // Delta
427 comp->GetParameter(2), // Xi
428 comp->GetParameter(3), // sigma
429 0);
430 part1->Save(minE,maxE,0,0,0,0);
431 dist->GetListOfFunctions()->Add(part1);
432
433 TF1* part2 = static_cast<TF1*>(seed->Clone("part2"));
434 part2->SetLineColor(kBlue+1);
435 part2->SetLineWidth(4);
436 part2->SetRange(minE, maxE);
437 part2->SetParameters(comp->GetParameter(4), // C
438 comp->GetParameter(1), // Delta
439 comp->GetParameter(5), // Xi
440 comp->GetParameter(3), // sigma
441 0);
442 part2->Save(minE,maxE,0,0,0,0);
443 dist->GetListOfFunctions()->Add(part2);
444#endif
445 return comp;
446}
447
448#endif
449// Local Variables:
450// mode: C++
451// End: