00001 #include "MultiHistogramFitFCN.h" 00002 00003 #include <cmath> 00004 #include <iostream> 00005 #include <cassert> 00006 00007 MultiHistogramFitFCN::MultiHistogramFitFCN(double refine_factor): 00008 fRefineFactor(refine_factor){ 00009 } 00010 00011 MultiHistogramFitFCN::~MultiHistogramFitFCN() { 00012 } 00013 00014 double MultiHistogramFitFCN::HistogramDetails_t::GetHeight(double t)const{ 00015 int bin=t - fTimeOffset; 00016 double remainder=t - fTimeOffset - bin; 00017 assert( remainder<1 ); 00018 double y0 = fTemplateHist->GetBinContent(bin); 00019 double y1 = fTemplateHist->GetBinContent(bin+1); 00020 return (y0 + remainder*((y1-y0)))*fAmplitudeScale; 00021 } 00022 00023 double MultiHistogramFitFCN::HistogramDetails_t::GetError2(double t)const{ 00024 int bin= t - fTimeOffset; 00025 double error= fTemplateHist->GetBinError(bin); 00026 return error*error; 00027 } 00028 00029 double MultiHistogramFitFCN::operator() (const std::vector<double>& par) const { 00030 // Chi2 fit with pedestal P, amplitude A, and timing T 00031 // Warning: The time is truncated to an int, so if there's 00032 // so if the step size in MINUIT is smalled than 1, 00033 // Any value of T will probably be seen as minimized, which it 00034 // almost certainly will not be. 00035 UnpackParameters(par); 00036 double chi2 = 0.; 00037 00038 int safety = 6*fRefineFactor; // remove a few bins from the fit 00039 int bounds[2]; 00040 GetHistogramBounds(safety,bounds[0], bounds[1]); 00041 00042 if( (bounds[1]-bounds[0]) < 40*fRefineFactor ) throw Except::SlimlyOverlappingTemplates(); 00043 00044 // Calculate the degrees of freedom ( #data - #fit_params) 00045 // +1 because we include both ends of the bounds when we loop through 00046 fNDoF = ((bounds[1] - bounds[0] + 1)/fRefineFactor) - par.size(); 00047 00048 double tpl_height,tpl_error; 00049 for (int i = bounds[0]+(fRefineFactor/2.0); i <= bounds[1]-(fRefineFactor/2.0); i += fRefineFactor) { 00050 // calculate the chi^2 based on the centre of the 5 bins to avoid getting 00051 // abonus from mathcing all 5. We shift and scale the template so that it 00052 // matches the pulse. This is because, when we have a normalised template, 00053 // we will get the actual amplitude, pedestal and time from the fit and not 00054 // just offsets 00055 tpl_height=0; 00056 tpl_error=0; 00057 00058 for(TemplateList::const_iterator i_tpl=fTemplates.begin(); 00059 i_tpl!=fTemplates.end(); ++i_tpl){ 00060 tpl_height+=i_tpl->GetHeight(i); 00061 tpl_error+=i_tpl->fAmplitudeScale*i_tpl->GetError2(i); 00062 } 00063 00064 double delta = fPulseHist->GetBinContent(i) - tpl_height; 00065 chi2 += delta*delta / tpl_error; 00066 } 00067 00068 return chi2; 00069 }