1 #ifndef ALILANDAUGAUSFITTER_H
2 #define ALILANDAUGAUSFITTER_H
4 * @file AliLandauGausFitter.h
5 * @author Christian Holm Christensen <cholm@nbi.dk>
6 * @date Tue Mar 11 08:56:03 2014
8 * @brief Declaration and implementation of fitter of Landau-Gauss
9 * distributions to energy loss spectra.
11 * @ingroup pwglf_forward
13 #include <AliLandauGaus.h>
17 #include <TObjArray.h>
20 #include <TFitResult.h>
24 * Fit Landau-Gauss distributions to energy loss distributions
28 * @ingroup pwglf_forward
30 class AliLandauGausFitter
34 * Enumeration of parameters
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
51 kA = AliLandauGaus::kA
54 * Get the fit options to use
56 * @return Fit options used through-out
58 static const char* GetFitOptions() { return "RNS"; }
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
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)
70 fFitResults.SetOwner();
71 fFunctions.SetOwner();
77 virtual ~AliLandauGausFitter()
83 * Enable/disable debugging output.
85 * @param debug If true, enable debugging output
87 void SetDebug(Bool_t debug=true) { fDebug = debug; }
89 * Clear internal arrays
98 * Fit a 1-particle signal to the passed energy loss distribution
100 * Note that this function clears the internal arrays first
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)
107 * @return The function fitted to the data
109 TF1* Fit1Particle(TH1* dist, Double_t sigman=-1);
111 * Fit a N-particle signal to the passed energy loss distribution
113 * If there's no 1-particle fit present, it does that first
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)
121 * @return The function fitted to the data
123 TF1* FitNParticle(TH1* dist, UShort_t n, Double_t sigman=-1);
125 * Fit a composite distribution of energy loss from both primaries
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.
133 * @return Function fitted to the data
135 TF1* FitComposite(TH1* dist, Double_t sigman);
137 * Get Lower cut on data
139 * @return Lower cut on data
141 Double_t GetLowCut() const { return fLowCut; }
143 * Get Maximum range to fit
145 * @return Maximum range to fit
147 Double_t GetMaxRange() const { return fMaxRange; }
149 * Get Number of bins from maximum to fit 1st peak
151 * @return Number of bins from maximum to fit 1st peak
153 UShort_t GetMinusBins() const { return fMinusBins; }
155 * Get Array of fit results
157 * @return Array of fit results
159 const TObjArray& GetFitResults() const { return fFitResults; }
161 * Get Array of fit results
163 * @return Array of fit results
165 TObjArray& GetFitResults() { return fFitResults; }
167 * Get Array of functions
169 * @return Array of functions
171 const TObjArray& GetFunctions() const { return fFunctions; }
173 * Get Array of functions
175 * @return Array of functions
177 TObjArray& GetFunctions() { return fFunctions; }
180 * Set parameter limits on the function @a f. The limits are only
181 * set if @f$ low \le test \le high@f$
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
189 void SetParLimits(TF1* f, Int_t iPar, Double_t test,
190 Double_t low, Double_t high)
192 if (test < low || test > high) {
193 ::Warning("","Initial value of %s=%f not in [%f,%f]",
194 f->GetParName(iPar), test, low, high);
198 ::Info(/*"SetParLimits"*/"", "Set par limits on %-12s=%f: [%f,%f]",
199 f->GetParName(iPar), test, low, high);
200 f->SetParLimits(iPar, low, high);
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
211 //____________________________________________________________________
213 AliLandauGausFitter::Fit1Particle(TH1* dist, Double_t sigman)
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),
222 dist->GetXaxis()->SetRange(cutBin, maxBin);
223 // dist->GetXaxis()->SetRangeUser(fLowCut, fMaxRange);
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();
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);
236 Int_t minEb = dist->GetXaxis()->FindBin(minE);
237 Int_t maxEb = dist->GetXaxis()->FindBin(maxE);
238 Double_t intg = dist->Integral(minEb, maxEb);
240 ::Warning("Fit1Particle",
241 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
242 dist->GetName(), minE, maxE, minEb, maxEb, intg);
247 dist->GetXaxis()->SetRange(1, maxBin);
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
255 f->FixParameter(kSigmaN, 0);
257 SetParLimits(f, kSigmaN, peakE, 0, rmsE);
260 TString opts(Form("%s%s", GetFitOptions(), fDebug ? "" : "Q"));
261 // Do the fit, getting the result object
263 ::Info(/*"Fit1Particle"*/"", "Fitting in the range %f,%f", minE, maxE);
264 TFitResultPtr r = dist->Fit(f, opts, "", minE, maxE);
266 ::Warning("Fit1Particle",
267 "No fit returned when processing %s in the range [%f,%f] "
268 "options %s", dist->GetName(), minE, maxE, opts.Data());
271 // f->SetRange(minE, fMaxRange);
272 fFitResults.AddAtAndExpand(new TFitResult(*r), 0);
273 fFunctions.AddAtAndExpand(f, 0);
277 //____________________________________________________________________
279 AliLandauGausFitter::FitNParticle(TH1* dist, UShort_t n, Double_t sigman)
281 // Get the seed fit result
282 TFitResult* r = static_cast<TFitResult*>(fFitResults.At(0));
283 TF1* f = static_cast<TF1*>(fFunctions.At(0));
285 f = Fit1Particle(dist, sigman);
286 r = static_cast<TFitResult*>(fFitResults.At(0));
288 ::Warning("FitNLandau", "No first shot at landau fit");
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();
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);
304 ::Warning("FitNParticle",
305 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
306 dist->GetName(), minE, maxEi, minEb, maxEb, intg);
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),
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);
326 SetParLimits(f,kSigmaN, f->GetParameter(kSigmaN), 0, rmsE);
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);
334 TString opts(Form("%s%s", GetFitOptions(), fDebug ? "" : "Q"));
336 ::Info(/*"FitNParticle"*/"",
337 "Fitting in the range %f,%f (%d)", minE, maxEi, n);
338 TFitResultPtr tr = dist->Fit(f, opts, "", minE, maxEi);
340 // f->SetRange(minE, fMaxRange);
341 fFitResults.AddAtAndExpand(new TFitResult(*tr), n-1);
342 fFunctions.AddAtAndExpand(f, n-1);
346 //____________________________________________________________________
348 AliLandauGausFitter::FitComposite(TH1* dist, Double_t sigman)
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),
354 dist->GetXaxis()->SetRange(cutBin, maxBin);
356 // Get the bin with maximum
357 Int_t peakBin = dist->GetMaximumBin();
358 Double_t peakE = dist->GetBinLowEdge(peakBin);
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);
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);
371 ::Warning("Fit1Particle",
372 "Integral of %s between [%f,%f] [%03d,%03d] = %f < 0",
373 dist->GetName(), minE, maxE, minEb, maxEb, intg);
378 dist->GetXaxis()->SetRange(1, maxBin);
380 // Define the function to fit
381 TF1* seed = AliLandauGaus::MakeF1(1,peakE,peakE/10,peakE/5,sigman,minE,maxE);
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);
390 // Do the fit, getting the result object
392 ::Info(/*"FitComposite"*/"", "Fitting seed in the range %f,%f", minE, maxE);
393 /* TFitResultPtr r = */ dist->Fit(seed, GetFitOptions(), "", minE, maxE);
395 maxE = dist->GetXaxis()->GetXmax();
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),
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);
413 // Do the fit, getting the result object
414 TString opts(Form("%s%s", GetFitOptions(), fDebug ? "" : "Q"));
416 ::Info("FitComposite", "Fitting composite in the range %f,%f", minE, maxE);
417 /* TFitResultPtr r = */ dist->Fit(comp, opts, "", minE, maxE);
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
430 part1->Save(minE,maxE,0,0,0,0);
431 dist->GetListOfFunctions()->Add(part1);
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
442 part2->Save(minE,maxE,0,0,0,0);
443 dist->GetListOfFunctions()->Add(part2);