#include "TPeakFit.h"
#include "TStopwatch.h"
ClassImp(TPeakFit)
int _NF_ = 0;
int _FIRST_ = 0;
TH1* _HIST_=0;
TF1* _F_[MAXFUNC1];
float _Y_[MAXFUNC1];
int _I0_;
int _I1_;
bool _SAMEWIDTH_;
float _CHI2_;
float _NP_;
void _CHI_(Int_t& npar, Double_t* gin, Double_t &f, Double_t *par, Int_t iflag)
{
int i,n,s,ss = 0;
Double_t chi = 0;
float X,Y,EY,EX,F,N=0;
float W = 0;
for(i=0;i<_NF_;i++)
{
if(_F_[i]) n = _F_[i]->GetNpar(); else n = 0;
for(s=0;s<n;s++)
{
if(_SAMEWIDTH_)
{
if(s==2)
{
if(i==_FIRST_) W = par[ss+s];
par[ss+s] = W;
}
}
if(_F_[i]) _F_[i]->SetParameter(s,par[ss+s]);
}
ss+=n;
}
for(i = 0;i<(_I1_-_I0_);i++)
{
X = _HIST_->GetBinCenter(_I0_+i);
Y = _HIST_->GetBinContent(_I0_+i);
EY = _HIST_->GetBinError(_I0_+i);
EX = _HIST_->GetBinWidth(_I0_+i)/2.0;
if(EY<=0) EY=1;
F = 0;
for(n=0;n<_NF_;n++) if(_F_[n]) F+=_F_[n]->Eval(X);
chi += (Y-F)*(Y-F)/(EY*EY+EX*EX);
N++;
}
f = chi;
_NP_ = N;
_CHI2_ = f;
return;
}
TPeakFit::TPeakFit():TObject()
{
mFunctions = new TContainer();
mFunctions->empty();
mHist = NULL;
mBack = NULL;
mNP = 0;
mMaxBackDegree = 1000;
setPeakVar(7);
setWidthVar(7);
setMinArea(0.1);
setMaxArea(10);
setMinAssym(0.1);
setMaxAssym(2.0);
setSameWidth(false);
setAssymOnOff(false);
setIndependentBack(false);
setBackVar(0.2);
mSum = NULL;
fCov = 0;
fCovSqrt = 0;
}
TPeakFit::~TPeakFit()
{
delete mFunctions;
mFunctions = NULL;
if(mSum) {delete mSum; mSum=NULL;}
if(fCov) delete [] fCov;
if(fCovSqrt) delete []fCovSqrt;
}
void TPeakFit::setBackground(int N,float* x,float* y)
{
if(mBack) delete mBack;
mBack = NULL;
if(N<=0) return;
mBack = new TGraph(N,x,y);
mMaxBackDegree = N;
}
void TPeakFit::addPeak(float amp, float avg, float sig, float ass)
{
mNP++;
char name[30];
sprintf(name,"Peak%03d",mNP);
TF1* f = new TF1(name,
"[0]*(exp(-0.5*((x-[1])/([2]*[3]))*((x-[1])/([2]*[3])))*(x<=[1])+exp(-0.5*((x-[1])/[2])*((x-[1])/[2]))*(x>[1]))"
,mFitMin,mFitMax);
f->SetParameters(amp,avg,sig,ass);
mFunctions->remove(name);
mFunctions->add(f);
return;
}
TF1* TPeakFit::getPeak(int p)
{
char name[30];
sprintf(name,"Peak%03d",p);
return (TF1*)mFunctions->get(name);
}
void TPeakFit::fitBack()
{
int i;
int N;
float x[2],y[2];
if(!mHist) return;
if(mBackDegree<0)
{
TF1 *f = new TF1("back","0",mFitMin,mFitMax);
mFunctions->remove("back");
mFunctions->add(f);
return;
}
if(mBackDegree>=mMaxBackDegree) mBackDegree=mMaxBackDegree-1;
if(!mBack && mBackDegree>=0)
{
if(mBackDegree>1) mBackDegree = 1;
N = 2;
x[0] = mFitMin;
x[1] = mFitMax;
y[0] = mHist->GetBinContent(mHist->FindBin(x[0]));
y[1] = mHist->GetBinContent(mHist->FindBin(x[1]));
setBackground(N,x,y);
}
char name[15];
sprintf(name,"pol%d",mBackDegree);
TF1 *f = new TF1("back",name,mFitMin,mFitMax);
if(mBack) mBack->Fit(f,"RQN");
mFunctions->remove("back");
mFunctions->add(f);
return;
}
void TPeakFit::fit()
{
int i,j,npar,s,n,ierr;
float p,pmin,pmax;
int B = -1;
Double_t arg[100];
bool FIXED[100];
Double_t P,E;
if(!mHist) return;
if(fCov) { delete [] fCov; fCov =0;}
if(fCovSqrt) { delete []fCovSqrt; fCovSqrt = 0;}
fitBack();
_NF_ = 0;
npar = 0;
for(i=0;i<MAXFUNC1;i++) _F_[i] = NULL;
if(getBack()) {_F_[_NF_] = getBack(); npar+=_F_[_NF_]->GetNpar(); B = _NF_; _NF_++; }
bool firstPeak = false;
for(i = 0;i<mNP;i++) if(getPeak(i+1))
{
_F_[_NF_] = getPeak(i+1);
npar+=_F_[_NF_]->GetNpar();
if(!firstPeak) {_FIRST_ = _NF_; firstPeak = true;}
_NF_++;
}
mNP = _NF_;
_SAMEWIDTH_ = mSameWid;
_I0_ = mHist->FindBin(mFitMin);
_I1_ = mHist->FindBin(mFitMax);
_HIST_ = mHist;
TMinuit *m = new TMinuit(npar);
arg[0] = -1;
m->mnexcm("SET PRI",arg,1,ierr);
m->mnexcm("SET NOWARNINGS",arg,1,ierr);
m->mnexcm("SET ERR",arg,1,ierr);
m->SetFCN(_CHI_);
s = 0;
for(i=0;i<_NF_;i++)
{
if(_F_[i]) n = _F_[i]->GetNpar(); else n = 0;
for(j=0;j<n;j++)
{
FIXED[s+j] = false;
if(_F_[i]) p = _F_[i]->GetParameter(j); else p = 0;
if (j==0 && i!=B) {pmin = mMinArea*p; pmax = mMaxArea*p;}
if (j==1 && i!=B) {pmin = p-mPeakVar; pmax = p+mPeakVar;}
if (j==2 && i!=B) {pmin = p-mWidVar; pmax = p+mWidVar;}
if (j==3 && i!=B) {pmin = mMinAssym; pmax = mMaxAssym;}
if (j==3 && !mAssym && i!=B) { p = 1; pmin = 1; pmax = 1; FIXED[s+j] = true;};
if (i==B && p>0) { pmin = (1-mBackVar)*p; pmax = (1+mBackVar)*p; }
if (i==B && p<0) { pmin = (1+mBackVar)*p; pmax = (1-mBackVar)*p; }
if (i==B && p==0){ pmin = -mBackVar; pmax = mBackVar; }
if (i==B && mBackMode)
{
pmin = p;
pmax = p;
FIXED[s+j] = true;
}
m->mnparm(s+j,"",p,(pmax-pmin)/5,pmin,pmax,ierr);
}
s+=n;
}
arg[0] = 500;
arg[1] = 1;
m->mnexcm("MIG",arg,2,ierr);
fCov = new double[npar*npar];
fCovSqrt = new double[npar*npar];
m->mnemat(fCov, npar);
for(i=0;i<npar;i++)
{
if(FIXED[i]) for(int j = 0;j<n;j++)
{
fCov[(i*npar)+j] = 0;
fCov[(j*npar)+i] = 0;
}
}
CalcCOVSqrt(npar);
mNPAR = npar;
s = 0;
for(i=0;i<_NF_;i++)
{
if(_F_[i]) n = _F_[i]->GetNpar(); else n = 0;
for(j=0;j<n;j++)
{
m->GetParameter(s+j,P,E);
if(_F_[i])
{
_F_[i]->SetParameter(j,P);
_F_[i]->SetParError(j,E);
if(mSameWid && _F_[i]!=getBack() && j==2)
{
_F_[i]->SetParameter(j,_F_[_FIRST_]->GetParameter(j));
_F_[i]->SetParError(j,_F_[_FIRST_]->GetParError(j));
}
}
}
s+=n;
}
mChi = _CHI2_;
mNDF = _NP_ - m->GetNumFreePars();
print();
}
void TPeakFit::CalcCOVSqrt(int NP)
{
double *C = fCovSqrt;
double *V = fCov;
for( int i = 0; i < NP; ++i )
{
for( int j = 0; j < NP; ++j )
{
C[i*NP+j] = 0;
}
}
for( int j = 0; j < NP; ++j )
{
double Ck = 0;
for( int k = 0; k < j; ++k )
{
Ck += C[j*NP+k] * C[j*NP+k];
}
C[j*NP+j] = sqrt( fabs( V[j*NP+j] - Ck ) );
for( int i = j+1; i < NP; ++i )
{
Ck = 0;
for( int k = 0; k < j; ++k )
{
Ck += C[i*NP+k] * C[j*NP+k];
}
if(C[j*NP+j]!=0 ) C[i*NP+j] = ( V[i*NP+j] - Ck ) / C[j*NP+j];
else C[i*NP+j] = 0;
}
}
return;
}
void TPeakFit::draw(TVirtualPad* pad)
{
if(!mHist) return;
if(pad) pad->cd();
int i,j,npar,s,n,ierr;
float p,pmin,pmax;
int i0,i1,nb;
if(mSum) { delete mSum; mSum = NULL;}
i0 = mHist->FindBin(mFitMin);
i1 = mHist->FindBin(mFitMax);
nb = (i1-i0)*5;
mSum = new TH1F("totalFit","",nb,mFitMin,mFitMax);
gROOT->RecursiveRemove(mSum);
if(getBack())
{
getBack()->SetLineWidth(2);
getBack()->SetLineColor(3);
getBack()->Draw("same");
mSum->Add(getBack(),1);
}
for(i = 0;i<mNP;i++) if(getPeak(i+1))
{
getPeak(i+1)->SetLineWidth(2);
getPeak(i+1)->SetLineColor(4);
getPeak(i+1)->Draw("same");
mSum->Add(getPeak(i+1),1);
}
mSum->SetLineColor(2);
mSum->SetLineWidth(2);
mSum->Draw("sameL");
if(pad) pad->Update();
}
void TPeakFit::print()
{
int n,i,j;
TString l,g;
Double_t p[100],e[100],p1[100],p2[100];
float a,a1,a2,b;
int NP = mNPAR;
char line[100];
log(10,"\n--------------------------------------------------------------");
log(10,"Results from last fit");
log(10,"");
log(10,"Number of peaks = %d Background type = %d",mNP,mBackDegree);
log(10,"Fit Min = %f Fit Max = %f",mFitMin,mFitMax);
log(10,"Chi = %f NDF = %f Chi/NDF = %f",mChi,mNDF,mChi/mNDF);
log(10,"");
if(fCov)
{
log(10,"Covariance matrix for this fit");
log(10,"------------------------------");
for(i = 0; i<NP; i++)
{
g=" ";
for(j = 0; j<NP; j++) g += Form("+%7.4e ",fCov[i*NP+j]);
log(10,g.Data());
}
log(10,"");
}
if(getBack())
{
TF1 *f = getBack();
log(10,"Background parameters");
n = f->GetNpar();
for(i=0;i<n;i++)
log(10,"P%02d = %7.4e +- %7.4e",i,f->GetParameter(i),f->GetParError(i));
}
log(10,"");
log(10,"Peak parameters");
for(j=0;j<mNP;j++) if(getPeak(j+1))
{
log(10,"-------- Peak number %d",j);
TF1 *f = getPeak(j+1);
n = f->GetNpar();
for(i=0;i<n;i++)
{
if(i==0) l = "AMPLITUDE";
if(i==1) l = "PEAK POS ";
if(i==2) l = "WIDTH ";
if(i==3) l = "ASYMMETRY";
p[i] = f->GetParameter(i);
e[i] = f->GetParError(i);
p1[i] = p[i]+e[i];
p2[i] = p[i]-e[i];
log(10,"%s = %7.4e +- %7.4e",l.Data(),p[i],e[i]);
}
l = "Integral ";
a2 = f->Integral(mFitMin,mFitMax,p2);
a1 = f->Integral(mFitMin,mFitMax,p1);
a = f->Integral(mFitMin,mFitMax,p);
log(10,"%s = %7.4e +- %7.4e",l.Data(),a,fabs(a2-a1)/2.);
if(mHist)
{
b = mHist->GetBinWidth(mHist->FindBin(p[1]));
l = "Counts ";
log(10,"%s = %7.4e +- %7.4e (histogram bin width = %5.2e)",l.Data(),a/b,fabs(a2-a1)/(2.*b),b);
}
}
}