/* Author: Anders G. Knospe, The University of Texas at Austin Created: 28 January 2014 This macro is a simple implementation of a Voigtian peak fit atop a background. A Voigtian peak is a convolution of a Breit-Wigner peak and a Gaussian. Here, it is implemented using the TMath::Voigt() function in ROOT. Input Parameters: h: input histogram containing a peak formula: character string containing the functional form of the background, as it would be implemented in a TF1. For example, a quadratic background can be implemented as "pol2(0)" or "[0]+[1]*x+[2]*x*x". par: array containing peak parameters {mass,resolution,width} fix: array containing three flags {fix mass,fix resolution,fix width}, which allow any of these peak parameters to be fixed during the fit range: array containing four values {R1,R2,R3,R4} R1 (R4) is the lower (upper) limit of the fit range R2 (R3) is the lower (upper) limit of the peak range. The peak range is excluded from the fit initially so that the background can be estimated. The peak range is included in all subsequent fits. file: file to which results may be saved (optional) */ int VoigtianFit(TH1D* h,char* formula,double* par,int* fix,double* range,TFile* file) { if(!h){cerr<<"Error in VoigtianFit(): missing histogram"<<endl; return 1;} char name[500]; sprintf(name,h->GetName()); cout<<"using VoigtianFit():\n h="<<name<<"\n background formula="<<formula<<endl; cout<<" mass="<<par[0]; if(fix[0]) cout<<" (fixed)"<<endl; else cout<<" (free)"<<endl; cout<<" resolution="<<par[1]; if(fix[1]) cout<<" (fixed)"<<endl; else cout<<" (free)"<<endl; cout<<" width="<<par[2]; if(fix[2]) cout<<" (fixed)"<<endl; else cout<<" (free)"<<endl; cout<<" range="<<range[0]<<" "<<range[1]<<" "<<range[2]<<" "<<range[3]<<endl; if(file) cout<<" file="<<file->GetName()<<endl; else cout<<" output not saved"<<endl; int j; //create copy of histogram h with peak removed TH1D* a=(TH1D*) h->Clone(Form("%s_nopeak",name)); for(j=h->GetXaxis()->FindBin(1.000001*range[1]);j<=h->GetXaxis()->FindBin(0.999999*range[2]);j++){ a->SetBinContent(j,0.); a->SetBinError(j,0.); } //get initial estimate of background TF1* fb=new TF1(Form("%s_back",name),formula,range[0],range[3]); a->Fit(fb,"RQN"); //define peak fit function int vp=fb->GetNpar(); TF1* fp=new TF1(Form("%s_peak",name),Form("%s+[%i]*TMath::Voigt(x-[%i],[%i],[%i])",formula,vp,vp+1,vp+2,vp+3),range[0],range[3]); //set initial parameter values, only the peak height is free for(j=0;j<vp;j++){fp->SetParameter(j,fb->GetParameter(j)); fp->FixParameter(j,fb->GetParameter(j));} fp->SetParameter(vp,h->GetBinContent(h->GetXaxis()->FindBin(0.5*(range[2]-range[1])))-fb->Eval(0.5*(range[2]-range[1]))); for(j=0;j<3;j++){fp->SetParameter(vp+j+1,par[j]); fp->FixParameter(vp+j+1,par[j]);} h->Fit(fp,"RQN"); if(!fix[2]){//release width fp->ReleaseParameter(vp+3); fp->SetParError(vp+3,0.1*fp->GetParameter(vp+3)); h->Fit(fp,"RQN"); } if(!fix[1]){//release resolution fp->ReleaseParameter(vp+2); fp->SetParError(vp+2,0.1*fp->GetParameter(vp+2)); h->Fit(fp,"RQN"); } if(!fix[0]){//release mass fp->ReleaseParameter(vp+1); fp->SetParError(vp+1,0.1*fp->GetParameter(vp+1)); h->Fit(fp,"RQN"); } //release background constant parameter fp->ReleaseParameter(0); fp->SetParError(0,fb->GetParError(0)); h->Fit(fp,"RQN"); //release other background parameters for(j=1;j<vp;j++){ fp->ReleaseParameter(j); fp->SetParError(j,fb->GetParError(j)); } h->Fit(fp,"RQN"); //final fit cerr<<"doing final fit"<<endl; h->Fit(fp,"RNI"); //save output if(file){ file->cd(); h->Write(); a->Write(); fb->Write(); fp->Write(); } return 0; }