KaliVeda  1.13/01
Heavy-Ion Analysis Toolkit
KVMultiGaussIsotopeFit.cpp
Go to the documentation of this file.
2 #include "TGraph.h"
3 #include "TRandom.h"
4 #include <TCanvas.h>
5 
6 
9 
10 KVMultiGaussIsotopeFit::KVMultiGaussIsotopeFit(int z, int Ngauss, double PID_min, double PID_max, const KVNumberList& alist, std::vector<double> pidlist)
11  : TF1(Form("MultiGaussIsotopeFit_Z=%d", z), this, &KVMultiGaussIsotopeFit::FitFunc, PID_min, PID_max, total_number_parameters(Ngauss)),
12  Z{z},
13  Niso{Ngauss},
14  PIDmin{PID_min}, PIDmax{PID_max},
15  Alist{alist.GetArray()},
16  PIDlist{pidlist}
17 {
18  // Constructor used to initialize and prepare a new fit of isotope PID spectrum
19  FixParameter(0, Niso);
20  SetParLimits(fit_param_index::bkg_cst, -1.e+5, 1e+5);
21  SetParameter(fit_param_index::bkg_cst, 4.);
22  SetParName(fit_param_index::bkg_cst, "Norm");
23  SetParLimits(fit_param_index::bkg_slp, -10, 0);
24  SetParameter(fit_param_index::bkg_slp, -0.2);
25  SetParName(fit_param_index::bkg_slp, "Bkg. slope");
26  SetParName(fit_param_index::gauss_wid, "Sigma");
27  SetParLimits(fit_param_index::gauss_wid, min_sigma, max_sigma);
28  SetParameter(fit_param_index::gauss_wid, 0.1);
29 
30  TGraph pid_vs_a;
31  for (int ig = 1; ig <= Niso; ++ig) {
32  SetParName(get_gauss_norm_index(ig), Form("Norm. A=%d", Alist[ig - 1]));
33  SetParLimits(get_gauss_norm_index(ig), 1.e-3, 1.e+06);
35  SetParName(get_mass_index(ig, Niso), Form("A_%d", ig));
36  FixParameter(get_mass_index(ig, Niso), Alist[ig - 1]);
37 
38 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,24,0)
39  pid_vs_a.AddPoint(Alist[ig - 1], PIDlist[ig - 1]);
40 #else
41  pid_vs_a.SetPoint(pid_vs_a.GetN(), Alist[ig - 1], PIDlist[ig - 1]);
42 #endif
43  }
44 
45  // do initial fit of centroids
46  TF1 centroidFit("centroidFit", this, &KVMultiGaussIsotopeFit::centroid_fit, 0., 100., 3);
47  centroidFit.SetParLimits(0, -50, 50);
48  centroidFit.SetParameter(0, 0);
49  centroidFit.SetParLimits(1, 1.e-2, 5.);
50  centroidFit.SetParameter(1, 1.e-1);
51  centroidFit.SetParLimits(2, -2.e-2, 1.);
52  centroidFit.SetParameter(2, 1.e-3);
53  pid_vs_a.Fit(&centroidFit, "N");
54 
55  for (int i = 0; i < 3; ++i) {
56  FixParameter(fit_param_index::pidvsA_a0 + i, centroidFit.GetParameter(i));
57  SetParName(fit_param_index::pidvsA_a0 + i, Form("PIDvsA_a%d", i));
58  }
59 
61  SetLineWidth(2);
62  SetNpx(500);
63 }
64 
65 
66 
71 
72 KVMultiGaussIsotopeFit::KVMultiGaussIsotopeFit(int z, int Ngauss, double PID_min, double PID_max,
73  const KVNumberList& alist, double bkg_cst, double bkg_slp,
74  double gaus_wid, double pidvsa_a0, double pidvsa_a1, double pidvsa_a2)
75  : TF1(Form("MultiGaussIsotopeFit_Z=%d", z), this, &KVMultiGaussIsotopeFit::FitFunc, PID_min, PID_max, total_number_parameters(Ngauss)),
76  Z{z},
77  Niso{Ngauss},
78  PIDmin{PID_min}, PIDmax{PID_max},
79  Alist{alist.GetArray()}
80 {
81  // Constructor which can be used with existing fit results (not to perform new fits)
82  //
83  // Use SetGaussianNorm() to set the normalisation parameters for each gaussian
84 
85  SetParameter(0, Niso);
86  SetParameter(fit_param_index::bkg_cst, bkg_cst);
87  SetParameter(fit_param_index::bkg_slp, bkg_slp);
88  SetParameter(fit_param_index::gauss_wid, gaus_wid);
89  SetParameter(fit_param_index::pidvsA_a0, pidvsa_a0);
90  SetParameter(fit_param_index::pidvsA_a1, pidvsa_a1);
91  SetParameter(fit_param_index::pidvsA_a2, pidvsa_a2);
92 
93  SetParName(fit_param_index::bkg_cst, "Norm");
94  SetParName(fit_param_index::bkg_slp, "Bkg. slope");
95  SetParName(fit_param_index::gauss_wid, "Sigma");
96 
97  for (int ig = 1; ig <= Niso; ++ig) {
98  SetParName(get_gauss_norm_index(ig), Form("Norm. A=%d", Alist[ig - 1]));
99  SetParName(get_mass_index(ig, Niso), Form("A_%d", ig));
100  FixParameter(get_mass_index(ig, Niso), Alist[ig - 1]);
101  }
102  for (int i = 0; i < 3; ++i)
103  SetParName(fit_param_index::pidvsA_a0 + i, Form("PIDvsA_a%d", i));
104 
106  SetLineWidth(2);
107  SetNpx(500);
108 }
109 
110 
111 
114 
116  : KVMultiGaussIsotopeFit(Z, fitparams.GetIntValue("Ng"), fitparams.GetDoubleValue("PIDmin"),
117  fitparams.GetDoubleValue("PIDmax"), fitparams.GetStringValue("Alist"),
118  fitparams.GetDoubleValue("Bkg_cst"), fitparams.GetDoubleValue("Bkg_slp"),
119  fitparams.GetDoubleValue("GausWid"),
120  fitparams.GetDoubleValue("PIDvsA_a0"),
121  fitparams.GetDoubleValue("PIDvsA_a1"),
122  fitparams.GetDoubleValue("PIDvsA_a2"))
123 {
124  // initialize from previous fit with parameters stored in KVNameValueList
125  for (int ig = 1; ig <= fitparams.GetIntValue("Ng"); ++ig)
126  SetGaussianNorm(ig, fitparams.GetDoubleValue(Form("Norm_%d", ig)));
127 }
128 
129 
130 
133 
135 {
136  // Remove the graphical representation of this fit from the given pad
137 
138  auto old_fit = pad->FindObject(get_name_of_multifit(Z));
139  if (old_fit) delete old_fit;
140  for (auto a : Alist) {
141  UnDrawGaussian(Z, a, pad);
142  }
143 }
144 
145 
146 
149 
151 {
152  // Draw the overall fit plus the individual gaussians for each isotope
153 
155 
156  TF1 fgaus("fgaus", "gausn", PIDmin, PIDmax);
157  // give a different colour to each gaussian
158  auto cstep = TColor::GetPalette().GetSize() / (Niso + 1);
159  int ig = 1;
160  for (auto& a : Alist) {
162  fgaus.SetNpx(500);
163  fgaus.SetLineColor(TColor::GetPalette()[cstep * ig]);
164  fgaus.SetLineWidth(2);
165  fgaus.SetLineStyle(9);
166  fgaus.DrawCopy("same")->SetName(get_name_of_isotope_gaussian(Z, a));
167  ++ig;
168  }
169 }
170 
171 
172 
177 
178 int KVMultiGaussIsotopeFit::GetMostProbableA(double PID, double& P) const
179 {
180  // For a given PID, calculate the most probable value of \f$A\f$, P is its probability.
181  //
182  // \returns most probable \f$A\f$
183 
184  auto total = Eval(PID);
185  std::map<double, int> probabilities;
186  int ig = 1;
187  for (auto& a : Alist) {
188  probabilities[evaluate_gaussian(ig, PID) / total] = a;
189  ++ig;
190  }
191  // the largest probability is now the last element in the map:
192  // get a reverse iterator to the beginning of the reversed map
193  auto it = probabilities.rbegin();
194  P = it->first;
195  return it->second;
196 }
197 
198 
199 
204 
205 double KVMultiGaussIsotopeFit::GetMeanA(double PID) const
206 {
207  // for a given PID, calculate the mean value of \f$A\f$ from the weighted sum of all gaussians
208  //
209  // \returns mean value of \f$A\f$
210 
211  auto total = Eval(PID);
212  int ig = 1;
213  double amean(0), totprob(0);
214  for (auto& a : Alist) {
215  auto weight = evaluate_gaussian(ig, PID) / total;
216  amean += weight * a;
217  totprob += weight;
218  ++ig;
219  }
220  return totprob > 0 ? amean / totprob : -1.;
221 }
222 
223 
224 
230 
231 std::map<int, double> KVMultiGaussIsotopeFit::GetADistribution(double PID) const
232 {
233  // For the given PID, the map is filled with all possible values of \f$A\f$
234  // and the associated probability.
235  //
236  // \returns std::map containing probability distribution \f$P(A|PID)\f$
237 
238  auto total = Eval(PID);
239  std::map<int, double> Adist;
240  int ig = 1;
241  for (auto& a : Alist) {
242  Adist[a] = evaluate_gaussian(ig, PID) / total;
243  ++ig;
244  }
245  return Adist;
246 }
247 
248 
249 
262 
263 int KVMultiGaussIsotopeFit::GetA(double PID, double& P) const
264 {
265  // Probabilistic method to determine \f$A\f$ from PID.
266  //
267  // The A returned will be drawn at random from the probability distribution given by the
268  // sum of all gaussians (and the background) for the given PID.
269  //
270  // The result of the draw may be that this PID is part of the background noise:
271  // in this case we return 0
272  //
273  // P is the probability of the chosen result.
274  //
275  // \returns randomly drawn \f$A\f$ for given PID
276 
277  auto total = Eval(PID);
278  double p_tot = 0;
279  int ig = 1;
280  auto X = gRandom->Uniform();
281  for (auto& a : Alist) {
282  auto w = evaluate_gaussian(ig, PID) / total;
283  p_tot += w;
284  if (X < w) {
285  P = w;
286  return a;
287  }
288  X -= w;
289  ++ig;
290  }
291  P = 1. - p_tot;
292  return 0; // background noise
293 }
294 
295 
296 
302 
303 double KVMultiGaussIsotopeFit::GetProbability(int A, double PID) const
304 {
305  // \param[in] A isotope mass number
306  // \param[in] PID value of PID associated with A
307  // \return the probability that A is the correct mass number for a given PID value
308  // \return zero if A is not associated with a Gaussian in the fit
309 
310  auto it = std::find(std::begin(Alist), std::end(Alist), A);
311  if (it != std::end(Alist)) {
312  int ig = std::distance(std::begin(Alist), it);
313  return evaluate_gaussian(ig, PID) / Eval(PID);
314  }
315  return 0;
316 }
317 
318 
319 
320 
321 
324 
325 void KVMultiGaussIsotopeFit::SetFitRange(double min, double max)
326 {
327  // Change range of fit
328 
329  SetRange(min, max);
330  PIDmin = min;
331  PIDmax = max;
332 }
333 
334 
336 
ClassImp(KVPartitionList) void KVPartitionList
Initialisation.
#define e(i)
const char Option_t
kBlack
R__EXTERN TRandom * gRandom
char * Form(const char *fmt,...)
Function for fitting PID mass spectra.
static TString get_name_of_isotope_gaussian(int z, int a)
static TString get_name_of_multifit(int z)
int get_mass_index(int ig, int ng) const
double GetGaussianWidth(int) const
double evaluate_gaussian(int i, double pid) const
double GetCentroid(int i) const
int Z
atomic number of the isotopes
int get_gauss_norm_index(int ig) const
std::map< int, double > GetADistribution(double PID) const
void SetFitRange(double min, double max)
Change range of fit.
void SetGaussianNorm(int i, double v)
int GetA(double PID, double &P) const
int GetMostProbableA(double PID, double &P) const
double GetProbability(int A, double PID) const
double GetGaussianNorm(int i) const
double centroid_fit(double *x, double *p)
int Niso
number of isotopes to fit = number of gaussians
double PIDmax
PID limits for current set of isotopes.
void UnDraw(TVirtualPad *pad=gPad) const
Remove the graphical representation of this fit from the given pad.
static void UnDrawGaussian(int z, int a, TVirtualPad *pad=gPad)
double GetMeanA(double PID) const
void DrawFitWithGaussians(Option_t *opt="") const
Draw the overall fit plus the individual gaussians for each isotope.
std::vector< int > Alist
list of masses of isotopes (in increasing order)
std::vector< double > PIDlist
list of initial centroid (PID) of each isotope (in increasing order)
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
Int_t GetIntValue(const Char_t *name) const
Double_t GetDoubleValue(const Char_t *name) const
Strings used to represent a set of ranges of values.
Definition: KVNumberList.h:83
Int_t GetSize() const
virtual void SetLineStyle(Style_t lstyle)
virtual void SetLineWidth(Width_t lwidth)
virtual void SetLineColor(Color_t lcolor)
static const TArrayI & GetPalette()
virtual Double_t GetParameter(const TString &name) const
virtual void SetRange(Double_t xmin, Double_t xmax)
virtual void SetNpx(Int_t npx=100)
virtual void SetParLimits(Int_t ipar, Double_t parmin, Double_t parmax)
virtual void SetParName(Int_t ipar, const char *name)
virtual TF1 * DrawCopy(Option_t *option="") const
virtual void SetParameters(const Double_t *params)
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
virtual void SetParameter(const TString &name, Double_t value)
virtual void FixParameter(Int_t ipar, Double_t value)
virtual void AddPoint(Double_t x, Double_t y)
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Int_t GetN() const
virtual TFitResultPtr Fit(const char *formula, Option_t *option="", Option_t *goption="", Axis_t xmin=0, Axis_t xmax=0)
virtual void SetName(const char *name)
virtual TObject * FindObject(const char *name) const
virtual Double_t Uniform(Double_t x1, Double_t x2)
auto * a