40 |
|
// configurable options |
41 |
|
bool ignorezero = false; // ignore zero bins when fitting |
42 |
|
|
43 |
– |
int ngauss; // number of Gaussians in current model |
44 |
– |
|
43 |
|
struct histo { |
44 |
|
vector< vector<double> > bins; |
45 |
|
double Xlo, Xhi, Ylo, Yhi; |
56 |
|
mdef = _mdef; |
57 |
|
} |
58 |
|
|
59 |
< |
int get_ngauss() { |
59 |
> |
int model_def::get_ngauss() { |
60 |
|
return ngauss; |
61 |
|
} |
62 |
|
|
63 |
< |
void set_ngauss(int _ngauss) { |
63 |
> |
void model_def::set_ngauss(int _ngauss) { |
64 |
|
ngauss = _ngauss; |
65 |
|
} |
66 |
|
|
67 |
|
// fit function |
68 |
< |
double fit_fcn(double x, double y, double *xval) { |
69 |
< |
int npar_indiv = mdef->get_formula()->GetNpar(); |
68 |
> |
double model_def::fit_fcn(double x, double y, double *xval) { |
69 |
> |
int npar_indiv = get_formula()->GetNpar(); |
70 |
|
double val = 0.0; |
71 |
|
for (int i = 0; i < ngauss; i++) { |
72 |
< |
mdef->get_formula()->SetParameters(xval + i*npar_indiv); |
72 |
> |
get_formula()->SetParameters(xval + i*npar_indiv); |
73 |
|
val += mdef->get_formula()->Eval(x, y); |
74 |
|
} |
75 |
|
return val; |
77 |
|
|
78 |
|
// TF2-compatible fit function |
79 |
|
double fit_fcn_TF2(double *x, double *pval) { |
80 |
< |
double val = fit_fcn(x[0], x[1], pval); |
80 |
> |
double val = mdef->fit_fcn(x[0], x[1], pval); |
81 |
|
return val; |
82 |
|
} |
83 |
|
|
84 |
< |
// Integral of model formula / chisquare sigma |
85 |
< |
double formula_int(double xlo, double xhi, double ylo, double yhi, |
84 |
> |
// Integral of (model formula)^2 / chisquare sigma |
85 |
> |
double model_def::formula_int(double xlo, double xhi, double ylo, double yhi, |
86 |
|
double *pval, double XbinSize, double YbinSize, |
87 |
|
double *xval) { |
88 |
|
double xstep = (xhi - xlo) / static_cast<double>(20); |
90 |
|
|
91 |
|
double fsum = 0.0; |
92 |
|
double pval_old[256]; |
93 |
< |
int npar = mdef->get_formula()->GetNpar(); |
93 |
> |
int npar = get_formula()->GetNpar(); |
94 |
|
if (npar > 256) { |
95 |
|
cerr << "Parameter overload" << endl; |
96 |
|
return 0.0; |
97 |
|
} |
98 |
< |
mdef->get_formula()->GetParameters(pval_old); |
99 |
< |
mdef->get_formula()->SetParameters(pval); |
98 |
> |
get_formula()->GetParameters(pval_old); |
99 |
> |
get_formula()->SetParameters(pval); |
100 |
|
|
101 |
|
for (int i = 0; i < 20; i++) { |
102 |
|
for (int j = 0; j < 20; j++) { |
104 |
|
double y = (static_cast<double>(j) + 0.5)*ystep + ylo; |
105 |
|
double sig_cut = 1.0e-5; |
106 |
|
double nu = XbinSize * YbinSize * fit_fcn(x, y, xval); |
107 |
< |
double sigma = mdef->chisquare_error(nu) < sig_cut |
108 |
< |
? sig_cut : mdef->chisquare_error(nu); |
107 |
> |
double sigma = fabs(chisquare_error(0.0)) < sig_cut |
108 |
> |
? sig_cut : chisquare_error(0.0); |
109 |
|
|
110 |
< |
fsum += xstep * ystep * mdef->get_formula()->Eval(x, y) |
110 |
> |
fsum += pow(xstep * ystep * get_formula()->Eval(x, y), 2.0) |
111 |
|
/ sigma / sigma; |
112 |
|
} |
113 |
|
} |
114 |
|
|
115 |
< |
mdef->get_formula()->SetParameters(pval_old); |
115 |
> |
get_formula()->SetParameters(pval_old); |
116 |
|
return fsum; |
117 |
|
} |
118 |
|
|
128 |
|
// add errors in data points in histogram |
129 |
|
for (int i = 0; i < energy.bins.size(); i++) { |
130 |
|
for (int j = 0; j < energy.bins.at(i).size(); j++) { |
131 |
< |
double x = (static_cast<double>(i) + 0.5) * (energy.Xhi - energy.Xlo) |
131 |
> |
double x = (static_cast<double>(i) + 0.5) * (energy.Xhi - energy.Xlo) |
132 |
|
/ static_cast<double>(energy.bins.size()) + energy.Xlo; |
133 |
|
double y = (static_cast<double>(j) + 0.5) * (energy.Yhi - energy.Ylo) |
134 |
|
/ static_cast<double>(energy.bins.at(i).size()) + energy.Ylo; |
135 |
< |
double nu = fit_fcn(x, y, xval) * XbinSize * YbinSize; |
135 |
> |
double nu = mdef->fit_fcn(x, y, xval) * XbinSize * YbinSize; |
136 |
|
double sig_cut = 1.0e-5; |
137 |
< |
if (mdef->chisquare_error(nu) > sig_cut || !ignorezero) |
137 |
> |
if (fabs(mdef->chisquare_error(energy.bins.at(i).at(j))) > sig_cut || !ignorezero) { |
138 |
|
chisquare += pow(energy.bins.at(i).at(j) - nu, 2.0) |
139 |
< |
/ pow(mdef->chisquare_error(nu), 2.0); |
140 |
< |
else |
139 |
> |
/ pow(mdef->chisquare_error(energy.bins.at(i).at(j)), 2.0); |
140 |
> |
} |
141 |
> |
else { |
142 |
|
chisquare += pow(energy.bins.at(i).at(j) - nu, 2.0) |
143 |
|
/ pow(sig_cut, 2.0); |
144 |
+ |
} |
145 |
|
} |
146 |
|
} |
147 |
< |
|
147 |
> |
|
148 |
|
// add errors due to Gaussians outside histogram |
149 |
< |
double eps = 0.1; // accuracy set for this function |
150 |
< |
for (int i = 0; i < ngauss; i++) { |
151 |
< |
double *pval = xval+i*mdef->get_formula()->GetNpar(); |
149 |
> |
double eps = 0.01; // accuracy set for this function |
150 |
> |
for (int i = 0; i < mdef->get_ngauss(); i++) { |
151 |
> |
double *pval = xval+i*(mdef->get_formula()->GetNpar()); |
152 |
|
double par_x = pval[mdef->get_indiv_max_x()]; |
153 |
|
double par_y = pval[mdef->get_indiv_max_y()]; |
154 |
|
double par_sig = pval[3]; |
155 |
< |
double cutoff_rad = -log(eps * 2.0 * PI * par_sig * par_sig |
156 |
< |
/ pval[0]); |
155 |
> |
double cutoff_rad = sqrt(-log(eps * 2.0 * PI * par_sig * par_sig |
156 |
> |
/ pval[0]) * 2.0 * par_sig * par_sig); |
157 |
|
|
158 |
|
bool left = par_x < energy.Xlo + cutoff_rad; |
159 |
|
bool right = par_x > energy.Xhi - cutoff_rad; |
160 |
|
bool top = par_y > energy.Yhi - cutoff_rad; |
161 |
< |
bool bottom = par_y > energy.Ylo + cutoff_rad; |
161 |
> |
bool bottom = par_y < energy.Ylo + cutoff_rad; |
162 |
|
|
163 |
|
if (left) { |
164 |
|
double xlo = par_x - cutoff_rad; |
165 |
|
double xhi = energy.Xlo; |
166 |
|
double ylo = energy.Ylo; |
167 |
|
double yhi = energy.Yhi; |
168 |
< |
chisquare += formula_int(xlo, xhi, ylo, yhi, pval, |
168 |
> |
chisquare += 2.0*mdef->formula_int(xlo, xhi, ylo, yhi, pval, |
169 |
|
XbinSize, YbinSize, xval); |
170 |
|
} |
171 |
|
if (right) { |
173 |
|
double xhi = par_x + cutoff_rad; |
174 |
|
double ylo = energy.Ylo; |
175 |
|
double yhi = energy.Yhi; |
176 |
< |
chisquare += formula_int(xlo, xhi, ylo, yhi, pval, |
176 |
> |
chisquare += 2.0*mdef->formula_int(xlo, xhi, ylo, yhi, pval, |
177 |
|
XbinSize, YbinSize, xval); |
178 |
|
} |
179 |
|
if (top) { |
181 |
|
double xhi = right ? par_x + cutoff_rad : energy.Xhi; |
182 |
|
double ylo = energy.Yhi; |
183 |
|
double yhi = par_y + cutoff_rad; |
184 |
< |
chisquare += formula_int(xlo, xhi, ylo, yhi, pval, |
184 |
> |
chisquare += 2.0*mdef->formula_int(xlo, xhi, ylo, yhi, pval, |
185 |
|
XbinSize, YbinSize, xval); |
186 |
|
} |
187 |
|
if (bottom) { |
189 |
|
double xhi = right ? par_x + cutoff_rad : energy.Xhi; |
190 |
|
double ylo = par_y - cutoff_rad; |
191 |
|
double yhi = energy.Ylo; |
192 |
< |
chisquare += formula_int(xlo, xhi, ylo, yhi, pval, |
192 |
> |
chisquare += 2.0*mdef->formula_int(xlo, xhi, ylo, yhi, pval, |
193 |
|
XbinSize, YbinSize, xval); |
194 |
|
} |
195 |
|
} |
196 |
< |
|
196 |
> |
|
197 |
|
fcnval = chisquare; |
198 |
|
} |
199 |
|
catch (exception ex) { |
481 |
|
} |
482 |
|
} |
483 |
|
|
484 |
< |
void par_init(TH2 *hist, TMinuit *gMinuit, vector<TString> &pars, |
484 |
> |
void fill_histo_with_vec(TH2 *hist, vector< vector<double> > &vec) { |
485 |
> |
for (int i = 0; i < vec.size(); i++) { |
486 |
> |
for (int j = 0; j < vec[i].size(); j++) { |
487 |
> |
hist->SetBinContent(i+1, j+1, vec[i][j]); |
488 |
> |
} |
489 |
> |
} |
490 |
> |
} |
491 |
> |
|
492 |
> |
void model_def::par_init(TH2 *hist, TMinuit *gMinuit, vector<TString> &pars, |
493 |
|
double *pval, double *perr, double *plo, double *phi, |
494 |
|
int npar, results r) { |
495 |
< |
int npar1 = npar - mdef->get_formula()->GetNpar(); |
495 |
> |
int npar1 = npar - get_formula()->GetNpar(); |
496 |
|
bool init_spec_pars = false; |
497 |
< |
if (ngauss <= mdef->get_n_special_par_sets()) { |
497 |
> |
if (ngauss <= get_n_special_par_sets()) { |
498 |
|
init_spec_pars = true; |
499 |
|
for (int k = 0; k < ngauss; k++) { |
500 |
< |
int ipar0 = k*mdef->get_formula()->GetNpar(); // index of par 0 |
501 |
< |
for (int l = 0; l < mdef->get_formula()->GetNpar(); l++) { |
500 |
> |
int ipar0 = k*get_formula()->GetNpar(); // index of indiv par 0 |
501 |
> |
for (int l = 0; l < get_formula()->GetNpar(); l++) { |
502 |
|
int ipar = ipar0 + l; |
503 |
|
if (ipar < npar) |
504 |
< |
mdef->get_special_par(k, l, pval[ipar], perr[ipar], plo[ipar], |
504 |
> |
get_special_par(k, l, pval[ipar], perr[ipar], plo[ipar], |
505 |
|
phi[ipar]); |
506 |
|
else |
507 |
|
cerr << "WARNING: Attempt to set parameter out of index range!" |
517 |
|
vector< vector<double> > sub_energy(energy.bins.size()); |
518 |
|
double max_sub, max_x = 0.0, max_y = 0.0; |
519 |
|
double pval_other[256]; |
520 |
< |
max_sub = -(numeric_limits<double>::infinity()); |
520 |
> |
max_sub = -(numeric_limits<double>::max()); |
521 |
|
for (int i = 0; i < energy.bins.size(); i++) { |
522 |
|
sub_energy[i].resize(energy.bins[i].size()); |
523 |
|
for (int j = 0; j < energy.bins[i].size(); j++) { |
526 |
|
double y = static_cast<double>(j)*(energy.Yhi - energy.Ylo) |
527 |
|
/ static_cast<double>(energy.bins[i].size()) + energy.Ylo; |
528 |
|
if (ngauss > 1) { |
529 |
< |
// subtract 4*sigma plus integral of fit function |
529 |
> |
// subtract integral of fit function |
530 |
|
try { |
531 |
|
int npval_other = r.pval.at(r.pval.size()-1).size(); |
532 |
|
if (npval_other > 256) { |
539 |
|
ngauss--; |
540 |
|
double nu = fit_fcn(x, y, pval_other) * XbinSize * YbinSize; |
541 |
|
ngauss++; |
542 |
< |
sub_energy[i][j] = energy.bins[i][j] - nu |
535 |
< |
- 4.0*mdef->chisquare_error(nu); |
542 |
> |
sub_energy[i][j] = energy.bins[i][j] - nu; |
543 |
|
} |
544 |
|
catch (exception ex) { |
545 |
|
cerr << "Exception in par_init" << endl; |
548 |
|
else { |
549 |
|
sub_energy[i][j] = energy.bins[i][j]; |
550 |
|
} |
544 |
– |
if (sub_energy[i][j] > max_sub) { |
545 |
– |
max_sub = sub_energy[i][j]; |
546 |
– |
max_x = x; |
547 |
– |
max_y = y; |
548 |
– |
} |
551 |
|
} |
552 |
|
} |
553 |
+ |
TH2D *hist_sub = new TH2D("hist_sub", "Subtracted histo", |
554 |
+ |
sub_energy.size(), energy.Xlo, |
555 |
+ |
energy.Xhi, |
556 |
+ |
sub_energy[0].size(), energy.Ylo, |
557 |
+ |
energy.Yhi); |
558 |
+ |
fill_histo_with_vec(hist_sub, sub_energy); |
559 |
+ |
max_sub = 0.0; |
560 |
+ |
max_x = 0.0; |
561 |
+ |
max_y = 0.0; |
562 |
+ |
for (int i = 1; i <= hist_sub->GetXaxis()->GetNbins(); i++) { |
563 |
+ |
for (int j = 1; j <= hist_sub->GetYaxis()->GetNbins(); j++) { |
564 |
+ |
double nu = energy.bins[i-1][j-1] - sub_energy[i-1][j-1]; |
565 |
+ |
if (hist_sub->GetBinContent(i, j) |
566 |
+ |
- 3.0*pow(chisquare_error(nu), 2.0) > max_sub) { |
567 |
+ |
max_sub = hist_sub->GetBinContent(i, j); |
568 |
+ |
max_x = static_cast<double>(i-1)*XbinSize |
569 |
+ |
+ hist_sub->GetXaxis()->GetXmin(); |
570 |
+ |
max_y = static_cast<double>(j-1)*YbinSize |
571 |
+ |
+ hist_sub->GetYaxis()->GetXmin(); |
572 |
+ |
} |
573 |
+ |
} |
574 |
+ |
} |
575 |
|
|
576 |
|
for (int i = npar1; i < npar; i++) { |
577 |
< |
if (mdef->get_indiv_max_E() == i - npar1) { |
578 |
< |
double nu = 0.0; |
579 |
< |
if (ngauss > 1) { |
556 |
< |
nu = fit_fcn(max_x, max_y, pval_other) * XbinSize * YbinSize; |
557 |
< |
} |
558 |
< |
pval[i] = max_sub + (ngauss > 1 ? 4.0*mdef->chisquare_error(nu) |
559 |
< |
: 0.0); |
560 |
< |
perr[i] = mdef->chisquare_error(pval[i])*0.1; |
577 |
> |
if (get_indiv_max_E() == i - npar1) { |
578 |
> |
pval[i] = max_sub / XbinSize / YbinSize; |
579 |
> |
perr[i] = mdef->chisquare_error(pval[i])*0.5; |
580 |
|
plo[i] = 0.0; |
581 |
|
phi[i] = 1.0e6; |
582 |
|
} |
583 |
< |
else if (mdef->get_indiv_max_x() == i - npar1) { |
583 |
> |
else if (get_indiv_max_x() == i - npar1) { |
584 |
|
pval[i] = max_x; |
585 |
|
perr[i] = (energy.Xhi - energy.Xlo) / static_cast<double>(hist->GetXaxis()->GetNbins()); |
586 |
|
plo[i] = 0.0; |
587 |
|
phi[i] = 0.0; |
588 |
|
} |
589 |
< |
else if (mdef->get_indiv_max_y() == i - npar1) { |
589 |
> |
else if (get_indiv_max_y() == i - npar1) { |
590 |
|
pval[i] = max_y; |
591 |
|
perr[i] = (energy.Yhi - energy.Ylo) / static_cast<double>(hist->GetYaxis()->GetNbins()); |
592 |
|
plo[i] = 0.0; |
594 |
|
} |
595 |
|
else { |
596 |
|
string dummy; |
597 |
< |
mdef->get_indiv_par(i-npar1, dummy, pval[i], perr[i], plo[i], phi[i]); |
597 |
> |
get_indiv_par(i-npar1, dummy, pval[i], perr[i], plo[i], phi[i]); |
598 |
|
} |
599 |
|
} |
600 |
|
} |
601 |
< |
int n_pars_to_set = init_spec_pars ? ngauss*mdef->get_formula()->GetNpar() |
601 |
> |
int n_pars_to_set = init_spec_pars ? ngauss*get_formula()->GetNpar() |
602 |
|
: npar - npar1; |
603 |
|
int init_par_to_set = init_spec_pars ? 0 : npar1; |
604 |
|
for (int i = 0; i < n_pars_to_set; i++) { |
605 |
|
double dummy; |
606 |
|
string s; |
607 |
|
int ipar = i + init_par_to_set; |
608 |
< |
mdef->get_indiv_par(i % mdef->get_formula()->GetNpar(), s, |
608 |
> |
get_indiv_par(i % get_formula()->GetNpar(), s, |
609 |
|
dummy, dummy, dummy, dummy); |
610 |
|
ostringstream par_oss; |
611 |
< |
par_oss << s << ipar / (mdef->get_formula()->GetNpar()) << flush; |
611 |
> |
par_oss << s << ipar / (get_formula()->GetNpar()) << flush; |
612 |
|
try { |
613 |
|
pars.at(ipar) = TString(par_oss.str()); |
614 |
|
} |
625 |
|
} |
626 |
|
} |
627 |
|
|
628 |
< |
results fit_histo(TH2 *hist, vector<trouble> &t_vec, |
629 |
< |
void (*cc_minuit)(TMinuit *, TH2 *, int), |
630 |
< |
int start_ngauss, |
631 |
< |
int rebinX, int rebinY, |
632 |
< |
double P_cutoff_val) { |
628 |
> |
results model_def::fit_histo(TH2 *hist, vector<trouble> &t_vec, |
629 |
> |
void (*cc_minuit)(TMinuit *, TH2 *, int), |
630 |
> |
int start_ngauss, |
631 |
> |
int rebinX, int rebinY, |
632 |
> |
double P_cutoff_val) { |
633 |
> |
set_model_def(this); |
634 |
|
TMinuit *gMinuit = new TMinuit(); |
635 |
|
int npar_indiv = mdef->get_formula()->GetNpar(); |
636 |
|
int istat, erflg; |
637 |
|
results r; |
638 |
+ |
r.moddef = this; |
639 |
|
|
640 |
|
gMinuit->SetFCN(fcn); |
641 |
|
gMinuit->mninit(5, 6, 7); |
675 |
|
for (ngauss = start_ngauss; |
676 |
|
ngauss <= (MAX_GAUSS > start_ngauss ? MAX_GAUSS : start_ngauss); |
677 |
|
ngauss++) { |
678 |
+ |
|
679 |
|
t_vec.resize(t_vec.size() + 1); |
680 |
|
int npar = npar_indiv*ngauss; |
681 |
|
double pval[256], perr[256], plo[256], phi[256]; |
687 |
|
|
688 |
|
// initialize parameters |
689 |
|
par_init(hist, gMinuit, pars, pval, perr, plo, phi, npar, r); |
690 |
< |
|
690 |
> |
|
691 |
|
// minimize |
692 |
|
double chisquare, edm, errdef; |
693 |
|
int nvpar, nparx; |
694 |
|
trouble t; |
695 |
|
t.occ = T_NULL; |
696 |
|
t.istat = 3; |
697 |
< |
// fix the N values and sigmas of the Gaussians |
697 |
> |
// fix sigmas of the Gaussians |
698 |
|
for (int i = 0; i < ngauss; i++) { |
699 |
|
double parno[2]; |
700 |
< |
parno[0] = i*npar_indiv + 1; |
701 |
< |
parno[1] = i*npar_indiv + 4; |
680 |
< |
gMinuit->mnexcm("FIX", parno, 2, erflg); |
700 |
> |
parno[0] = i*npar_indiv + 4; |
701 |
> |
gMinuit->mnexcm("FIX", parno, 1, erflg); |
702 |
|
} |
703 |
|
gMinuit->mnexcm("SIMPLEX", 0, 0, erflg); |
704 |
|
gMinuit->mnexcm("MIGRAD", 0, 0, erflg); |
684 |
– |
// release N values, fix mu_x and mu_y |
685 |
– |
for (int i = 0; i < ngauss; i++) { |
686 |
– |
double parno[4]; |
687 |
– |
parno[0] = i*npar_indiv + 1; |
688 |
– |
parno[1] = i*npar_indiv + 2; |
689 |
– |
parno[2] = i*npar_indiv + 3; |
690 |
– |
parno[3] = i*npar_indiv + 4; |
691 |
– |
gMinuit->mnexcm("RELEASE", parno, 1, erflg); |
692 |
– |
gMinuit->mnexcm("FIX", parno+1, 2, erflg); |
693 |
– |
} |
694 |
– |
gMinuit->mnexcm("MIGRAD", 0, 0, erflg); |
695 |
– |
// release mu_x and mu_y |
696 |
– |
for (int i = 0; i < ngauss; i++) { |
697 |
– |
double parno[4]; |
698 |
– |
parno[0] = i*npar_indiv + 1; |
699 |
– |
parno[1] = i*npar_indiv + 2; |
700 |
– |
parno[2] = i*npar_indiv + 3; |
701 |
– |
parno[3] = i*npar_indiv + 4; |
702 |
– |
gMinuit->mnexcm("RELEASE", parno+1, 2, erflg); |
703 |
– |
} |
704 |
– |
gMinuit->mnexcm("MIGRAD", 0, 0, erflg); |
705 |
|
gMinuit->mnstat(chisquare, edm, errdef, nvpar, nparx, istat); |
706 |
|
if (istat == 3) { |
707 |
|
/* we're not concerned about MINOS errors right now |
766 |
|
} |
767 |
|
ndof -= npar; |
768 |
|
|
769 |
+ |
r.chisquare.push_back(chisquare); |
770 |
|
double P = prob(chisquare, ndof); |
770 |
– |
cout << "P = "<<P << endl; |
771 |
|
if (P > P_cutoff_val) { |
772 |
|
break; |
773 |
|
} |