GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TLMFitter.cxx
Go to the documentation of this file.
1#include "TLMFitter.h"
2#include <iomanip>
3#include <iostream>
4
5/* DEFINITIONS */
6/*******************************************************************/
7/* alamda = parameter switches between curve and gradient method */
8/* must begin negative to initialize fit routine */
9/* x[DIM] = x values of the data */
10/* y[DIM] = y values of the data (Number of counts) */
11/* sig[i] = sigma in the y value */
12/* chisq = chi-squared definitions defined in mrqcof subroutine */
13/* sig2i = 1 over sigma squared (Used in computing the chisq) */
14/* a[i] = fit parameters of the fitting function */
15/* ia[i] = set to '1' to free a[i] or '0' for fixed */
16/* beta[j]= extremum vector */
17/* alpha[k][k] = curvature matrix */
18/* dy = yfit - ydata */
19/* ma = number of fit parameters in fit function */
20/*******************************************************************/
21
22/* Function Subroutine-***Put fitting function here***-------------*/
23void TLMFitter::funcs(const double& x, Vec_IO_double& a, double& y, Vec_O_double& dyda)
24{
25 for(int i = 0; i < a.size(); ++i) {
26 fFunction->SetParameter(i, a[i]);
27 }
28 for(int i = 0; i < a.size(); ++i) {
29 dyda[i] = fFunction->GradientPar(i, &x);
30 }
31 y = fFunction->Eval(x);
32 // std::cout<<"y: "<<y<<" x: "<<x<<std::endl;
33}
34
35void TLMFitter::Fit(TH1* hist, TF1* func)
36{
37 double alamda = 0.;
38 double chisq = 0.;
39 double ochisq = 0.;
40
41 int ma = func->GetNpar(); /* This is the number of parameters in fit function */
42 Mat_O_double alpha(ma, ma);
43 Mat_O_double covar(ma, ma);
44 Vec_BOOL ia(ma);
45 Vec_O_double a(ma);
46 Vec_O_double dyda(ma);
47
48 fFunction = func;
49 fHist = hist;
50
51 // Sets whether parameters are fixed or free.
52 std::cout << "Setting the parameters..." << std::endl;
53 for(int i = 0; i < func->GetNpar(); ++i) {
54 a[i] = func->GetParameter(i);
55
56 Double_t min = 0.;
57 Double_t max = 0.;
58 func->GetParLimits(i, min, max);
59 if(min == max) {
60 if(min != 0) {
61 // Parameter is fixed
62 ia[i] = false;
63 continue;
64 }
65 }
66 ia[i] = true;
67 }
68 for(int i = 0; i < ma; ++i) {
69 std::cout << "par[" << i << "] = " << fFunction->GetParameter(i) << std::endl;
70 }
71 double func_range_min = 0.;
72 double func_range_max = 0.;
73 func->GetRange(func_range_min, func_range_max);
74 std::cout << "function range: " << func_range_min << " to " << func_range_max << std::endl;
75 SetFitterRange(static_cast<int>(func_range_min), static_cast<int>(func_range_max)); // not sure why SetFitterRange takes int as arguments, is it expecting bins as input?
76 int bin_min = hist->FindBin(func_range_min);
77 int bin_max = hist->FindBin(func_range_max);
78
79 int nBins = hist->GetNbinsX();
80 Vec_double x(nBins);
81 Vec_double y(nBins);
82 Vec_double sig(nBins);
83 Vec_double yfit(nBins);
84 Vec_double W(nBins);
85 Vec_double v(nBins);
86
87 std::cout << "Setting bin values..." << std::endl;
88 std::cout << "Range is " << bin_min << " to " << bin_max << std::endl;
89 for(int i = 0; i < hist->GetNbinsX(); ++i) {
90 x[i] = hist->GetXaxis()->GetBinUpEdge(i + 1) * hist->GetXaxis()->GetBinWidth(1);
91 y[i] = hist->GetBinContent(i + 1);
92 v[i] = hist->GetBinError(i + 1) * hist->GetBinError(i + 1);
93 if(v[i] == 0) {
94 W[i] = 1.0;
95 } else {
96 W[i] = y[i] / v[i];
97 }
98 }
99
100 alamda = -1;
101 mrqmin(x, y, sig, a, ia, covar, alpha, chisq, W, alamda);
102 std::cout << "out of mrqmin" << std::endl;
103 int k = 1;
104 int itst = 0;
105 while(true) {
106 std::cout << std::endl
107 << "Iteration #" << std::setw(3) << k;
108 std::cout << std::setw(18) << "chi-squared:" << std::setw(13) << chisq;
109 std::cout << std::setw(11) << "alamda:" << std::setw(10) << alamda << std::endl;
110 for(int i = 0; i < ma; ++i) {
111 std::cout << "par[" << i << "] = " << fFunction->GetParameter(i) << std::endl;
112 }
113 std::cout << std::endl;
114 ++k;
115 ochisq = chisq;
116 mrqmin(x, y, sig, a, ia, covar, alpha, chisq, W, alamda);
117 std::fabs(ochisq - chisq) < 0.0001 ? itst++ : itst = 0;
118 if(itst < 10) {
119 continue;
120 }
121 alamda = 0.0;
122 mrqmin(x, y, sig, a, ia, covar, alpha, chisq, W, alamda);
123 std::cout << "Uncertainties:" << std::endl;
124 for(int i = 0; i < ma; ++i) {
125 std::cout << " " << std::sqrt(covar[i][i]);
126 }
127 std::cout << std::endl;
128 break;
129 }
130 std::cout << "Chis2/ndf: " << chisq << std::endl;
131
132 // Feed the parameters back into the function.
133 for(int i = 0; i < ma; ++i) {
134 fFunction->SetParameter(i, a[i]);
135 fFunction->SetParError(i, std::sqrt(covar[i][i]));
136 }
137}
138/*******************************************************************/
139/* */
140/* Subroutines below (in order) - */
141/* integrator - integration routine (fit function is an integral)/ */
142/* mrqmin - subroutine, which rejects or accepts fit parameters */
143/* mrqcof - calculates the chi squared values */
144/* covsrt - converts alpha matrix into the error matrix */
145/* gaussj - row reduces alpha and beta to send to covsrt */
146/* */
147/*******************************************************************/
148/*******************************************************************/
149/* Integrator */
150/*******************************************************************/
152 Vec_double& dyda, int chisqnumber, const double&, Vec_double& yfit, const int& bin)
153{
154 // Integrates the function within each bin
155 int ma = a.size();
156 // int i, j, k;
157 double ynew = 0;
158 double xstart = x[bin]; // This is the start of the bin
159 double ymod = 0;
161 Vec_double temp(dyda.size());
162
163 for(int k = 0; k < fIntegrationSteps; ++k) {
164 // Find the y value at different integration stpes along the bin
165 // z[k] = xstart + (double)(k)*bin_width/(double)fIntegrationSteps;
166 z[k] = xstart + static_cast<double>(k) / static_cast<double>(fIntegrationSteps);
167 funcs(z[k], a, ymod, dyda);
168 for(int i = 0; i < ma; ++i) {
169 // Integrates the gradient of the functon within the bin
170 temp[i] += 1. / static_cast<double>(fIntegrationSteps) * dyda[i];
171 // temp[i] += bin_width/(double)fIntegrationSteps*dyda[i];
172 }
173 // integrates the y of the function
174 // ynew += bin_width/(double)fIntegrationSteps*ymod;
175 ynew += 1. / static_cast<double>(fIntegrationSteps) * ymod;
176 }
177 // Sets the actual variables to the "temporary" variables used for integration
178 for(int i = 0; i < ma; ++i) {
179 dyda[i] = temp[i];
180 }
181 yfit[bin] = ynew;
182
183 // //Change the chisqnumber from what it was defined at the beginning (most likely 3 = Poisson distribution)
184 // //to 2 (= Gaussian distribution with possible bin counts of zero) if yfit < 0.
185 if(yfit[bin] <= 0) {
186 chisqnumber = 2;
187 } else {
188 chisqnumber = fInitChi2Number;
189 }
190
191 /* Various definitions of sigma used in diff chi squares */
192 if(chisqnumber == 0 || chisqnumber == 3) {
193 sig[bin] = sqrt(yfit[bin]);
194 }
195 if(chisqnumber == 1 || chisqnumber == 2) {
196 sig[bin] = sqrt(y[bin]);
197 if(chisqnumber == 1) {
198 if(y[bin] <= 0.5) {
199 sig[bin] = sqrt(yfit[bin]);
200 }
201 }
202 if(chisqnumber == 2) {
203 if(y[bin] <= 0.5) {
204 sig[bin] = 1.0;
205 }
206 }
207 }
208 return chisqnumber;
209}
210///*******************************************************************/
211/* mrqmin */
212/*******************************************************************/
213
215 Mat_O_double& covar, Mat_O_double& alpha, double& chisq, Vec_I_double& W, double& alamda)
216{
217 static int mfit;
218 static double ochisq;
219 static double chisqexp;
220
221 int ma = a.size();
222 if(ma <= 0) {
223 std::cerr << __PRETTY_FUNCTION__ << ": vector a is empty, not doing anything!" << std::endl; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
224 return;
225 }
226 static Mat_double* oneda_p;
227 static Vec_double* atry_p;
228 static Vec_double* beta_p;
229 static Vec_double* da_p;
230 if(alamda < 0.0) { // Initialization
231 atry_p = new Vec_double(ma);
232 beta_p = new Vec_double(ma);
233 da_p = new Vec_double(ma);
234 mfit = 0;
235 for(int j = 0; j < ma; j++) {
236 if(ia[j]) {
237 mfit++;
238 }
239 oneda_p = new Mat_double(mfit, 1);
240 alamda = 0.001;
241 mrqcof(x, y, sig, a, ia, alpha, *beta_p, chisq, W, chisqexp);
242 ochisq = chisq;
243 for(j = 0; j < ma; j++) {
244 (*atry_p)[j] = a[j];
245 }
246 }
247 }
248 Mat_double& oneda = *oneda_p;
249 Vec_double& atry = *atry_p;
250 Vec_double& beta = *beta_p;
251 Vec_double& da = *da_p;
252 Mat_double temp(mfit, mfit);
253 // After linearized fitting matrix, by augmenting diagonal elements
254 for(int j = 0; j < mfit; j++) {
255 for(int k = 0; k < mfit; k++) {
256 covar[j][k] = alpha[j][k];
257 }
258 covar[j][j] = alpha[j][j] * (1.0 + alamda);
259 for(int k = 0; k < mfit; k++) {
260 temp[j][k] = covar[j][k];
261 }
262 oneda[j][0] = beta[j];
263 }
264 gaussj(temp, oneda); // Matrix solution
265 for(int j = 0; j < mfit; j++) {
266 for(int k = 0; k < mfit; k++) {
267 covar[j][k] = temp[j][k];
268 }
269 da[j] = oneda[j][0];
270 }
271 if(alamda == 0.0) { // Once converged, evaluate covariance matrix
272 covsrt(covar, ia, mfit);
273 covsrt(alpha, ia, mfit); // Spread out alpha to its full size too
274 chisqexp -= mfit;
275 chisq /= chisqexp;
276 delete oneda_p;
277 delete da_p;
278 delete beta_p;
279 delete atry_p;
280 return;
281 }
282 for(int j = 0, l = 0; l < ma; l++) { // Did the trial succeed?
283 if(ia[l]) {
284 atry[l] = a[l] + da[j++];
285 }
286 }
287 mrqcof(x, y, sig, atry, ia, covar, da, chisq, W, chisqexp);
288 if(chisq < ochisq) { // Success, accept the new solution
289 alamda *= 0.1;
290 ochisq = chisq;
291 for(int j = 0; j < mfit; j++) {
292 for(int k = 0; k < mfit; k++) {
293 alpha[j][k] = covar[j][k];
294 }
295 beta[j] = da[j];
296 }
297 for(int l = 0; l < ma; l++) {
298 a[l] = atry[l];
299 }
300 } else { // Failure, increase alamda and return
301 alamda *= 10.0;
302 chisq = ochisq;
303 }
304}
305
306/*******************************************************************/
307/* mrqcof */
308/*******************************************************************/
309
311 Mat_O_double& alpha, Vec_O_double& beta, double& chisq, Vec_I_double& W, double& chisqexp)
312{
313 chisqexp = 0.0;
314
315 int ndata = x.size();
316 int ma = a.size();
317 int mfit = 0;
318 Vec_double dyda(ma);
319 Vec_double yfit(ndata);
320 for(int j = 0; j < ma; j++) {
321 if(ia[j]) {
322 mfit++;
323 }
324 }
325 for(int j = 0; j < mfit; j++) { // Initialize (symmetric) alpha, beta.
326 for(int k = 0; k <= j; k++) {
327 alpha[j][k] = 0.0;
328 }
329 beta[j] = 0.0;
330 }
331 chisq = 0.0;
332 for(int i = fRangeMin; i < fRangeMax; ++i) { // Summation loop over all data.
333 int chisqnumber = integrator(x, y, sig, W, a, dyda, fInitChi2Number, fHist->GetXaxis()->GetBinWidth(1), yfit, i);
334 // funcs(x[i],a,ymod,dyda); Integrator does this instead
335 double sig2i = 1.0 / (sig[i] * sig[i]);
336 double dy = y[i] - yfit[i];
337 for(int j = 0, l = 0; l < ma; l++) {
338 if(ia[l]) {
339 // sigs are different for different chisqnumbers
340 // This is done in integrator
341 double wt = dyda[l] * sig2i;
342 for(int k = 0, m = 0; m < l + 1; m++) {
343 if(ia[m]) {
344 if(chisqnumber == 0) { // least squares
345 alpha[j][k++] += wt * dyda[m] * (1.0 + dy / yfit[i]) * (1.0 + dy / yfit[i]) * W[i];
346 } else {
347 alpha[j][k++] += wt * dyda[m] * W[i];
348 }
349 }
350 }
351 if(chisqnumber == 0) { // Least squares
352 beta[j++] += dy * wt * (1.0 + dy / (2.0 * yfit[i])) * W[i];
353 } else {
354 beta[j++] += dy * wt * W[i];
355 }
356 }
357 // Now find the correct chi^2 based on the different versions of chisquared
358 if((chisqnumber == 0) || (chisqnumber == 1) || (chisqnumber == 2)) {
359 chisq += dy * dy * sig2i * W[i];
360 chisqexp += 1;
361 }
362 if(chisqnumber == 3) {
363 if(y[i] < 1.0) {
364 chisq += 2.0 * (yfit[i] - y[i]) * W[i];
365 } else {
366 chisq += 2.0 * (yfit[i] - y[i] + y[i] * log(y[i] / yfit[i])) * W[i];
367 }
368
369 // approximation to expectation value of ml chi squared
370 if(yfit[i] < 4.2) {
371 chisqexp += -2.0 * yfit[i] * std::log(yfit[i]) + std::pow(yfit[i], 2.0) * std::log(4.0) -
372 std::pow(yfit[i], 3.0) * std::log(4.0 / 3.0) +
373 (1.0 / 3.0) * std::pow(yfit[i], 4.0) * std::log(32.0 / 27.0) -
374 (1.0 / 12.0) * std::pow(yfit[i], 5.0) * std::log(4096.0 / 3645.0) +
375 1442.633448 * std::pow(yfit[i], 6.0) / std::pow(10.0, 6.0) -
376 1782.46047 * std::pow(yfit[i], 7.0) / std::pow(10.0, 7.0) +
377 1588.98494 * std::pow(yfit[i], 8.0) / std::pow(10.0, 8.0) -
378 716.19428 * std::pow(yfit[i], 9.0) / std::pow(10.0, 9.0);
379 } else {
380 chisqexp += 1.0 + 1.0 / (6.0 * yfit[i]) + 1.0 / (6.0 * std::pow(yfit[i], 2.0)) +
381 19.0 / (60.0 * std::pow(yfit[i], 3.0)) + 9.0 / (10.0 * std::pow(yfit[i], 4.0)) -
382 31.9385 / std::pow(yfit[i], 5.0) + 741.3189 / std::pow(yfit[i], 6.0) -
383 3928.1260 / std::pow(yfit[i], 7.0) + 6158.3381 / std::pow(yfit[i], 8.0);
384 }
385 } // end of chi2 3
386 }
387 } // end of loop over data
388
389 for(int j = 1; j < mfit; j++) { // Fill in the symmetric side.
390 for(int k = 0; k < j; k++) {
391 alpha[k][j] = alpha[j][k];
392 }
393 }
394}
395
396/*******************************************************************/
397/* covsrt */
398/*******************************************************************/
399void TLMFitter::covsrt(Mat_IO_double& covar, Vec_I_BOOL& ia, const int mfit)
400{
401 // Rearranges the covariance matrix covar in the order of all ma parameters
402 int ma = ia.size();
403 for(int i = mfit; i < ma; i++) {
404 for(int j = 0; j < i + 1; j++) {
405 covar[i][j] = covar[j][i] = 0.0;
406 }
407 }
408 int k = mfit - 1;
409 for(int j = ma - 1; j >= 0; j--) {
410 if(ia[j]) {
411 for(int i = 0; i < ma; i++) {
412 SWAP(covar[i][k], covar[i][j]);
413 }
414 for(int i = 0; i < ma; i++) {
415 SWAP(covar[k][i], covar[j][i]);
416 }
417 k--;
418 }
419 }
420}
421
422/*******************************************************************/
423/* gaussj */
424/*******************************************************************/
425
427{
428 // Matrix solver
429 int n = a.nrows();
430 int m = b.ncols();
431
432 Vec_INT indxc(n);
433 Vec_INT indxr(n);
434 Vec_INT ipiv(n);
435 for(int j = 0; j < n; j++) {
436 ipiv[j] = 0;
437 }
438 int icol = 0;
439 int irow = 0;
440 for(int i = 0; i < n; i++) {
441 double big = 0.0;
442 for(int j = 0; j < n; j++) {
443 if(ipiv[j] != 1) {
444 for(int k = 0; k < n; k++) {
445 if(ipiv[k] == 0) {
446 if(std::fabs(a[j][k]) >= big) {
447 big = std::fabs(a[j][k]);
448 irow = j;
449 icol = k;
450 }
451 }
452 }
453 }
454 }
455 ++(ipiv[icol]);
456 if(irow != icol) {
457 for(int l = 0; l < n; l++) {
458 SWAP(a[irow][l], a[icol][l]);
459 }
460 for(int l = 0; l < m; l++) {
461 SWAP(b[irow][l], b[icol][l]);
462 }
463 }
464 indxr[i] = irow;
465 indxc[i] = icol;
466 if(a[icol][icol] == 0.0) {
467 nrerror("gaussj: Singular Matrix");
468 }
469 double pivinv = 1.0 / a[icol][icol];
470 a[icol][icol] = 1.0;
471 for(int l = 0; l < n; l++) {
472 a[icol][l] *= pivinv;
473 }
474 for(int l = 0; l < m; l++) {
475 b[icol][l] *= pivinv;
476 }
477 for(int ll = 0; ll < n; ll++) {
478 if(ll != icol) {
479 double dum = a[ll][icol];
480 a[ll][icol] = 0.0;
481 for(int l = 0; l < n; l++) {
482 a[ll][l] -= a[icol][l] * dum;
483 }
484 for(int l = 0; l < m; l++) {
485 b[ll][l] -= b[icol][l] * dum;
486 }
487 }
488 }
489 }
490 for(int l = n - 1; l >= 0; l--) {
491 if(indxr[l] != indxc[l]) {
492 for(int k = 0; k < n; k++) {
493 SWAP(a[k][indxr[l]], a[k][indxc[l]]);
494 }
495 }
496 }
497}
TH1D * hist
Definition UserFillObj.h:3
TH1 * fHist
Definition TLMFitter.h:615
void nrerror(const std::string &error_text)
Definition TLMFitter.h:638
void covsrt(Mat_IO_double &covar, Vec_I_BOOL &ia, int mfit)
int integrator(Vec_I_double &x, Vec_I_double &y, Vec_double &sig, Vec_I_double &W, Vec_IO_double &a, Vec_double &dyda, int chisqnumber, const double &bin_width, Vec_double &yfit, const int &bin)
void SetFitterRange(int min, int max)
Definition TLMFitter.h:632
int fIntegrationSteps
Definition TLMFitter.h:614
int fInitChi2Number
Definition TLMFitter.h:617
int fRangeMin
Definition TLMFitter.h:618
int fRangeMax
Definition TLMFitter.h:619
void mrqcof(Vec_I_double &x, Vec_I_double &y, Vec_double &sig, Vec_IO_double &a, Vec_I_BOOL &ia, Mat_O_double &alpha, Vec_O_double &beta, double &chisq, Vec_I_double &W, double &chisqexp)
TF1 * fFunction
Definition TLMFitter.h:616
void mrqmin(Vec_I_double &x, Vec_I_double &y, Vec_double &sig, Vec_IO_double &a, Vec_I_BOOL &ia, Mat_O_double &covar, Mat_O_double &alpha, double &chisq, Vec_I_double &W, double &alamda)
*******************************************************************‍/
void gaussj(Mat_IO_double &a, Mat_IO_double &b)
void funcs(const double &x, Vec_IO_double &a, double &y, Vec_O_double &dyda)
Definition TLMFitter.cxx:23
void Fit(TH1 *hist, TF1 *func)
Definition TLMFitter.cxx:35
int nrows() const
Definition TLMFitter.h:288
int ncols() const
Definition TLMFitter.h:294
int size() const
Definition TLMFitter.h:138
void SWAP(T &a, T &b)
Definition TLMFitter.h:557
NRVec< double > Vec_double
Definition TLMFitter.h:433
NRMat< double > Mat_double
Definition TLMFitter.h:490