00001 #include "CalibTracker/SiStripLorentzAngle/interface/SymmetryFit.h"
00002 #include <cmath>
00003 #include <cassert>
00004 #include "boost/foreach.hpp"
00005
00006 TH1* SymmetryFit::symmetryChi2(std::string basename, const std::vector<TH1*>& candidates, const std::pair<unsigned,unsigned> range)
00007 {
00008 TH1* fake = (TH1*)(candidates[0]->Clone(basename.c_str()));
00009 fake->Reset();
00010 SymmetryFit combined(fake,range);
00011 delete fake;
00012
00013 BOOST_FOREACH(const TH1* candidate, candidates) {
00014 SymmetryFit sf(candidate,range);
00015 combined+=sf;
00016 delete sf.chi2_;
00017 }
00018
00019 int status = combined.fit();
00020 if(status) { delete combined.chi2_; combined.chi2_=0;}
00021 return combined.chi2_;
00022 }
00023
00024 TH1* SymmetryFit::symmetryChi2(const TH1* candidate, const std::pair<unsigned,unsigned> range)
00025 {
00026 SymmetryFit sf(candidate, range);
00027 int status = sf.fit();
00028 if(status) { delete sf.chi2_; sf.chi2_=0; }
00029 return sf.chi2_;
00030 }
00031
00032 SymmetryFit::SymmetryFit(const TH1* h, const std::pair<unsigned,unsigned> r)
00033 : symm_candidate_(h),
00034 minDF_(r.second-r.first),
00035 range_(r),
00036 minmaxUsable_(findUsableMinMax()),
00037 ndf_( minmaxUsable_.first<minmaxUsable_.second ? minmaxUsable_.second-minmaxUsable_.first : 0),
00038 chi2_(0)
00039 {
00040 makeChi2Histogram();
00041 fillchi2();
00042 }
00043
00044 void SymmetryFit::makeChi2Histogram()
00045 {
00046 std::string XXname = name(symm_candidate_->GetName());
00047 unsigned Nbins = 2*( range_.second - range_.first ) + 1;
00048 double binwidth = symm_candidate_->GetBinWidth(1);
00049 double low = symm_candidate_->GetBinCenter(range_.first) - 3*binwidth/4;
00050 double up = symm_candidate_->GetBinCenter(range_.second-1) + 3*binwidth/4;
00051 chi2_ = new TH1F(XXname.c_str(),"", Nbins, low, up);
00052 }
00053
00054 std::pair<unsigned,unsigned> SymmetryFit::findUsableMinMax() const
00055 {
00056 unsigned NEAR(0), FAR(0);
00057 const std::vector<std::pair<unsigned,unsigned> > cont = continuousRanges();
00058 for(unsigned L=0; L<cont.size(); L++) { if( cont[L].first > range_.first) continue;
00059 for(unsigned R=L; R<cont.size(); R++) { if( cont[R].second < range_.second) continue;
00060
00061 const unsigned far = std::min( range_.first - cont[L].first,
00062 cont[R].second - range_.second );
00063 const unsigned near = std::max( range_.second<cont[L].second ? 0 : range_.second - cont[L].second,
00064 cont[R].first<range_.first ? 0 : cont[R].first - range_.first );
00065
00066 if ( (far>near) && (far-near)>(FAR-NEAR) ) { FAR = far; NEAR = near;}
00067 }
00068 }
00069 return std::make_pair(NEAR,FAR);
00070 }
00071
00072 std::vector<std::pair<unsigned,unsigned> > SymmetryFit::continuousRanges() const
00073 {
00074 std::vector<std::pair<unsigned,unsigned> > ranges;
00075 const unsigned Nbins = symm_candidate_->GetNbinsX();
00076 unsigned i=0;
00077 while(++i<=Nbins) {
00078 if(symm_candidate_->GetBinError(i)) {
00079 std::pair<unsigned,unsigned> range(i,i+1);
00080 while(++i<=Nbins && symm_candidate_->GetBinError(i)) range.second++;
00081 ranges.push_back(range);
00082 }
00083 }
00084 return ranges;
00085 }
00086
00087
00088 void SymmetryFit::fillchi2()
00089 {
00090 if(ndf_<minDF_) return;
00091
00092 for(int i=1; i<=chi2_->GetNbinsX() ; ++i) {
00093 const unsigned L( range_.first-1+(i-1)/2 ), R( range_.first+i/2 );
00094 chi2_->SetBinContent( i, chi2( std::make_pair(L,R)) );
00095 }
00096 }
00097
00098 float SymmetryFit::chi2(std::pair<unsigned,unsigned> point)
00099 {
00100 point.first -= minmaxUsable_.first;
00101 point.second += minmaxUsable_.first;
00102 float XX=0;
00103 unsigned i=ndf_;
00104 while(i-->0) {
00105 XX += chi2_element(point);
00106 point.first--;
00107 point.second++;
00108 }
00109 return XX;
00110 }
00111
00112 float SymmetryFit::chi2_element(std::pair<unsigned,unsigned> range)
00113 {
00114 float
00115 y0(symm_candidate_->GetBinContent(range.first)),
00116 y1(symm_candidate_->GetBinContent(range.second)),
00117 e0(symm_candidate_->GetBinError(range.first)),
00118 e1(symm_candidate_->GetBinError(range.second)); assert(e0&&e1);
00119
00120 return pow(y0-y1, 2)/(e0*e0+e1*e1);
00121 }
00122
00123 int SymmetryFit::fit() {
00124
00125 std::vector<double> p = pol2_from_pol3(chi2_);
00126 if( !p.size() ||
00127 p[0] < chi2_->GetBinCenter(1) ||
00128 p[0] > chi2_->GetBinCenter(chi2_->GetNbinsX()))
00129 return 7;
00130
00131 TF1* f = fitfunction();
00132 f->SetParameter(0, p[0]); f->SetParLimits(0, p[0], p[0]);
00133 f->SetParameter(1, p[1]); f->SetParLimits(1, p[1], p[1]);
00134 f->SetParameter(2, p[2]); f->SetParLimits(2, p[2], p[2]);
00135 f->SetParameter(3, ndf_); f->SetParLimits(3, ndf_,ndf_);
00136 chi2_->Fit(f,"WQ");
00137 return 0;
00138 }
00139
00140 TF1* SymmetryFit::fitfunction()
00141 {
00142 TF1* f = new TF1("SymmetryFit","((x-[0])/[1])**2+[2]+0*[3]");
00143 f->SetParName(0,"middle");
00144 f->SetParName(1,"uncertainty");
00145 f->SetParName(2,"chi2");
00146 f->SetParName(3,"NDF");
00147 return f;
00148 }
00149
00150
00151 std::vector<double> SymmetryFit::pol2_from_pol2(TH1* hist) {
00152 std::vector<double> v;
00153
00154 int status = hist->Fit("pol2","WQ");
00155 if(!status) {
00156 std::vector<double> p;
00157 p.push_back(hist->GetFunction("pol2")->GetParameter(0));
00158 p.push_back(hist->GetFunction("pol2")->GetParameter(1));
00159 p.push_back(hist->GetFunction("pol2")->GetParameter(2));
00160 if(p[2]>0) {
00161 v.push_back( -0.5*p[1]/p[2] );
00162 v.push_back( 1./sqrt(p[2]) );
00163 v.push_back( p[0]-0.25*p[1]*p[1]/p[2] );
00164 }
00165 }
00166 return v;
00167 }
00168
00169 std::vector<double> SymmetryFit::pol2_from_pol3(TH1* hist) {
00170 std::vector<double> v;
00171
00172 int status = hist->Fit("pol3","WQ");
00173 if(!status) {
00174 std::vector<double> p;
00175 p.push_back(hist->GetFunction("pol3")->GetParameter(0));
00176 p.push_back(hist->GetFunction("pol3")->GetParameter(1));
00177 p.push_back(hist->GetFunction("pol3")->GetParameter(2));
00178 p.push_back(hist->GetFunction("pol3")->GetParameter(3));
00179 double radical = p[2]*p[2] - 3*p[1]*p[3] ;
00180 if(radical>0) {
00181 double x0 = ( -p[2] + sqrt(radical) ) / ( 3*p[3] ) ;
00182 v.push_back( x0 );
00183 v.push_back( pow( radical, -0.25) );
00184 v.push_back( p[0] + p[1]*x0 + p[2]*x0*x0 + p[3]*x0*x0*x0 );
00185 }
00186 }
00187 return v;
00188 }