#include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include using namespace std; ClassImp(PamUnfold); PamUnfold::PamUnfold(TString name, TString title) : TNamed(name, title){ cout << "WARNING:: entering PamUnfold::PamUnfold(TString name, TString title)" << endl; cout << " empty constructor be sure to initialize measured and smearing" << endl; _measured = NULL; _smearing = NULL; _prior = NULL; } PamUnfold::~PamUnfold(){ } PamUnfold::PamUnfold(TString name, TString title, TH1D* measured, TH2D* smearing) : TNamed(name, title){ _measured = measured; _smearing = smearing; _prior = NULL; if( !IsBinningOK() ) cerr << " -- ERROR in PamUnfold::PamUnfold(TString name, TString title, TH1D* measured, TH2D* smearing)" << endl; if( !IsSmNormalized() ){ cerr << " -- WARNING in PamUnfold::PamUnfold(TString name, TString title, TH1D* measured, TH2D* smearing)" << endl; cerr << " ---- Remember to provide the normalization histogram for the smearing matrix" << endl; } Init(); _is_improved = kFALSE; _smooth = kFALSE; _smooth_opt = "ROOT"; _nsamples = 500; _max_steps = 50; _min_chi2 = 1.; } void PamUnfold::AddExcludedBin(Int_t bin){ _excluded_bins.push_back(bin); } TH1D* PamUnfold::GetMeasured(){ return _measured; } TH2D* PamUnfold::GetSmearing(){ return _smearing; } TH1D* PamUnfold::GetUnfolded(){ TH1D* __unfolded = (TH1D*) _unfolded->Clone( Form("%s_%s_unf", _measured->GetName(), this->GetName()) ); return __unfolded; } TList* PamUnfold::GetBinHistList(){ return _bin_hist_list; } void PamUnfold::SetMeasured(TH1D* measured){ _measured = measured; } void PamUnfold::SetSmearing(TH2D* smearing){ _smearing = smearing; if( !IsBinningOK() ) cerr << " -- ERROR in PamUnfold::SetSmearing(TH2D* smearing)" << endl; Init(); } void PamUnfold::SetPrior(TH1D* prior){ _prior = (TH1D*) prior->Clone( Form("_prior_%s", this->GetName()) ); if( !IsBinningOK() ) cerr << " -- ERROR in PamUnfold::SetPrior(TH1D* prior)" << endl; } void PamUnfold::SetNormalization(TH1D* norm){ _norm = norm; //If the matrix is not normalized it is normalized now. if( !IsSmNormalized() ){ cout << " Normalizing smearing matrix" << endl; try{ if(!_norm) throw 1; } catch(int e){ if(e==1){ cerr << " -- ERROR in PamUnfold::Init()" << endl; cerr << " ---- Normalization histogram is NULL" << endl; cerr << " execution is likely to crash." << endl; } } NormalizeMatrix(); } } void PamUnfold::SetImproved(Bool_t improv){ _is_improved = improv; } void PamUnfold::SetSmoothing(Bool_t smooth, TString smooth_opt){ _smooth = smooth; _smooth_opt = smooth_opt; if(!_smooth_opt.CompareTo("")) _smooth_opt = "ROOT"; } void PamUnfold::SetNsamples(UInt_t nsamples){ _nsamples = nsamples; } void PamUnfold::SetMaxSteps(UInt_t max_steps){ _max_steps = max_steps; } void PamUnfold::SetMinChi2(Double_t min_chi2){ _min_chi2 = min_chi2; } Bool_t PamUnfold::IsSmNormalized(){ Double_t sum = 0; for(UInt_t i=0; i<_smearing->GetNbinsX(); i++){ sum = 0; for(UInt_t j=0; j<_smearing->GetNbinsY(); j++) sum += _smearing->GetBinContent(_smearing->GetBin(i+1,j+1)); if(sum>1.0000001){ cout << "Bin: " << i+1 << " sum=" << sum << endl; return kFALSE; } } return kTRUE; } void PamUnfold::WMovAvSmooth(TH1D* input, vector&excl){ Double_t* xarr = new Double_t [input->GetNbinsX()]; for(UInt_t ib=0; ibGetNbinsX(); ib++) xarr[ib] = (Double_t) input->GetBinContent(ib+1); Bool_t excluding; for(UInt_t ib=1; ibGetNbinsX()-1; ib++){ excluding = kFALSE; for(UInt_t iex=0; iexSetBinContent(ib+1, (Float_t) x); } delete xarr; return; } Double_t PamUnfold::GetChi2H( TH1D* h1, TH1D* h2 ){ if(h1->GetNbinsX() != h2->GetNbinsX()){ cout << " -- Warning in PamUnfold::GetChi2H(TH1D*, TH1D*) : Histograms have different number of bins" << endl; return -1; } const Double_t* x_1 = h1->GetXaxis()->GetXbins()->GetArray(); const Double_t* x_2 = h2->GetXaxis()->GetXbins()->GetArray(); for(Int_t ib=0; ib < h1->GetNbinsX()+1; ib++){ if(x_1[ib] != x_2[ib]){ cout << " -- Warning in PamUnfold::GetChi2H(TH1D*, TH1D*) : Histograms have different number of bins" << endl; return -1; } else continue; } Double_t chi2 = 0; for(UInt_t i=0; iGetNbinsX(); i++){ if(h1->GetBinContent(i+1) + h2->GetBinContent(i+2) > 1) chi2 += pow(h1->GetBinContent(i+1) - h2->GetBinContent(i+1),2)/(h1->GetBinContent(i+1) + h2->GetBinContent(i+2)); else chi2 += pow(h1->GetBinContent(i+1) - h2->GetBinContent(i+1),2); } return chi2; } void PamUnfold::Unfold(){ //Smoothing is applied to the spectrum, not to the counts histogram!!! // ------------------------------------------------------ // Prior initialization // ------------------------------------------------------ for(Int_t i=0; i<_prior->GetNbinsX(); i++) _prior->SetBinContent(i+1, _prior->GetBinContent(i+1)/_prior->GetBinWidth(i+1) ); if(_smooth){ if(_smooth_opt.Contains("WMA")){ cout << " --- Using Weighted Moving Average smoothing\n"; WMovAvSmooth(_prior, _excluded_bins); } else if(_smooth_opt.Contains("ROOT")){ cout << " --- Using standard ROOT smoothing\n"; _prior->Smooth(); } else cout << " --- WARNING: No valid smoothing option specified" << endl; } for(Int_t i=0; i<_prior->GetNbinsX(); i++) _prior->SetBinContent(i+1, _prior->GetBinContent(i+1)*_prior->GetBinWidth(i+1) ); _prior->Scale(1./_prior->GetSumOfWeights()); //The prior is a 'probability' so it has to be normalized at the very last step // ------------------------------------------------------ // Unfolding // ------------------------------------------------------ cout << " --- UNFOLDING!!" << endl; TH2D* theta = (TH2D*) _smearing->Clone("theta"); theta->Reset(); for(Int_t i=0; iGetNbinsY(); i++){ for(Int_t j=0; jGetNbinsX(); j++){ Double_t s = _smearing->GetBinContent(_smearing->GetBin(i+1,j+1))*_prior->GetBinContent(i+1); Double_t ls = 0; for(Int_t k=0; k<_smearing->GetNbinsX(); k++) ls+=_smearing->GetBinContent(_smearing->GetBin(k+1,j+1))*_prior->GetBinContent(k+1); if(ls) theta->SetBinContent(theta->GetBin(j+1,i+1),s/ls); } } _unfolded->Reset(); for(Int_t i=0; i<_unfolded->GetNbinsX(); i++){ Double_t num = 0; Double_t den = 0; Double_t err = 0; for(Int_t j=0; jGetNbinsX(); j++){ num+=theta->GetBinContent( theta->GetBin(j+1,i+1) )*_measured->GetBinContent(j+1); den+=_smearing->GetBinContent(_smearing->GetBin(i+1,j+1)); err+=pow( theta->GetBinContent(theta->GetBin(j+1,i+1))*_measured->GetBinError(j+1), 1 ); // err+=pow( theta->GetBinContent(theta->GetBin(j+1,i+1))*sp->GetBinError(j+1), 2 ); } if(den){ _unfolded->SetBinContent(i+1, num/den); _unfolded->SetBinError(i+1, fabs(err)/den); // _unfolded->SetBinError(i+1,sqrt(err)/den); } } } void PamUnfold::ImprovedUnfold(){ vector mu(_measured->GetNbinsX()); //Smoothing is applied to the spectrum, not to the counts histogram!!! // ------------------------------------------------------ // Prior initialization // ------------------------------------------------------ for(Int_t i=0; i<_prior->GetNbinsX(); i++) _prior->SetBinContent(i+1, _prior->GetBinContent(i+1)/_prior->GetBinWidth(i+1) ); if(_smooth){ if(_smooth_opt.Contains("WMA")){ cout << " --- Using Weighted Moving Average smoothing\n"; WMovAvSmooth(_prior, _excluded_bins); } else if(_smooth_opt.Contains("ROOT")){ cout << " --- Using standard ROOT smoothing\n"; _prior->Smooth(); } else cout << " --- WARNING: No valid smoothing option specified" << endl; } for(Int_t i=0; i<_prior->GetNbinsX(); i++) _prior->SetBinContent(i+1, _prior->GetBinContent(i+1)*_prior->GetBinWidth(i+1) ); _prior->Scale(1./_prior->GetSumOfWeights()); //The prior is a 'probability' so it has to be normalized at the very last step // ------------------------------------------------------ // Unfolding // ------------------------------------------------------ cout << " --- UNFOLDING!!" << endl; _bin_list->Clear(); TMVA::Timer* timer = new TMVA::Timer(_nsamples, "unf"); for(UInt_t sample=0; sample<_nsamples; sample++){ cout << " ---- Sampling... " << timer->GetLeftTime(sample) << " left..." << endl << flush <<"\33[1A"; SampleMatrix(); TH2D* theta = (TH2D*) _smearing_sample->Clone("theta"); theta->Reset(); for(Int_t i=0; iGetNbinsY(); i++){ for(Int_t j=0; jGetNbinsX(); j++){ Double_t s = _smearing_sample->GetBinContent(_smearing_sample->GetBin(i+1,j+1))*_prior->GetBinContent(i+1); Double_t ls = 0; for(Int_t k=0; k<_smearing_sample->GetNbinsX(); k++) ls+=_smearing_sample->GetBinContent(_smearing_sample->GetBin(k+1,j+1))*_prior->GetBinContent(k+1); if(ls) theta->SetBinContent(theta->GetBin(j+1,i+1),s/ls); } } TVectorD* result = new TVectorD(_unfolded->GetNbinsX()); //Sampling mu_j and rounding to nearest integer for(Int_t j=0; j<_measured->GetNbinsX(); j++){ mu[j] = TMath::Nint( rangen->Gamma( 1 + _measured->GetBinContent(j+1), 1 ) ); vector theta_vec_j(_unfolded->GetNbinsX()); for(Int_t i=0; i<_unfolded->GetNbinsX(); i++){ theta_vec_j[i] = theta->GetBinContent( theta->GetBin(j+1,i+1) ); // cout << theta_vec_j[i] << " "; } // cout << endl; vector res_partial = rangen->Multinomial(mu[j], theta_vec_j); for(Int_t i=0; i<_unfolded->GetNbinsX(); i++){ // cout << res_partial[i] << " "; (*result)[i] += res_partial[i]; } // cout << endl; // cout << _measured->GetBinContent(j+1) << " " << mu[j] << " " << res_partial[17] << " " << (*result)[17] << endl; } for(Int_t i=0; i<_unfolded->GetNbinsX(); i++){ Double_t den = 0; for(Int_t j=0; j<_measured->GetNbinsX(); j++) den+=_smearing_sample->GetBinContent(_smearing_sample->GetBin(i+1,j+1)); (*result)[i] /= den; } _bin_list->Add(result); } BuildFlux(); } Bool_t PamUnfold::IsBinningOK(){ Int_t n_meas = _measured->GetNbinsX(); Int_t n_smy = _smearing->GetNbinsY(); if(n_meas != n_smy){ cerr << " --- Different binning between measured and smearing" << endl; cerr << " ---- measured: " << n_meas << " bins; smearing:" << n_smy << " bins on Y-axis" << endl; return kFALSE; } const Double_t* x_meas = _measured->GetXaxis()->GetXbins()->GetArray(); const Double_t* y_sm = _smearing->GetYaxis()->GetXbins()->GetArray(); for(Int_t ib=0; ib < n_meas+1; ib++){ if( fabs(x_meas[ib] - y_sm[ib])/x_meas[ib] > 1e-4 ){ cerr << " --- Different binning between measured and smearing" << endl; cerr << " ---- x_meas[" << ib << "] = " << x_meas[ib] << ";" <<" y_sm[" << ib << "] = " << y_sm[ib] << ";" << endl; return kFALSE; } else continue; } if(_prior){ Int_t n_prior = _prior->GetNbinsX(); Int_t n_smx = _smearing->GetNbinsX(); if(n_prior != n_smx){ cerr << " --- Different binning between prior and smearing" << endl; return kFALSE; } const Double_t* x_prior = _prior->GetXaxis()->GetXbins()->GetArray(); const Double_t* x_sm = _smearing->GetXaxis()->GetXbins()->GetArray(); for(Int_t ib=0; ib < n_prior+1; ib++){ if( fabs(x_prior[ib] - x_sm[ib])/x_sm[ib] > 1e-4 ){ cerr << " --- Different binning between prior and smearing" << endl; return kFALSE; } else continue; } } return kTRUE; } void PamUnfold::IterativeUnfolding(UInt_t niter, TList* list){ cout << " -- PamUnfold object " << this->GetName() << endl << " Starting unfolding"; if(!niter) cout << " with chi2 convergence check"; else cout << " with " << niter << " iterations"; if(_is_improved) cout << " and improved algorithm (may take a while...)"; else cout << " and standard algorithm"; cout << endl; if(list) cout << " Saving iterations to TList object at " << list << endl; UInt_t iiter = 0; Double_t chi2 = 1e6; Bool_t kFlag = kTRUE; while( kFlag ){ if(iiter > 0) SetPrior(_old_unfolded); if(_is_improved) ImprovedUnfold(); else Unfold(); if(iiter > 0){ chi2 = GetChi2H( _unfolded, _old_unfolded ); cout << " Chi2 of change from iteration " << iiter-1 << " to " << iiter << " = " << chi2 << endl; } if(!niter) kFlag = chi2 < _min_chi2 ? kFALSE : kTRUE; else kFlag = iiter == niter ? kFALSE : kTRUE; if(iiter >= _max_steps){ kFlag = kFALSE; cerr << "WARNING: Unfolding procedure did not converge in less than " << _max_steps << " steps\n"; } _old_unfolded = GetUnfolded(); _old_unfolded->SetName( Form("%s_%03i", _old_unfolded->GetName(), iiter) ); if(list){ list->Add( _old_unfolded ); } iiter++; } cout << " Unfolding converged" << endl; } void PamUnfold::Init(){ cout << " -- PamUnfold object " << this->GetName() << endl << " Initializing unfolded histogram" << endl; _unfolded = new TH1D( Form("%s_%s_u", _measured->GetName(), this->GetName()), "", _smearing->GetNbinsX(), _smearing->GetXaxis()->GetXbins()->GetArray()); _unfolded->Reset(); _prior = (TH1D*) _unfolded->Clone( Form("_prior_%s",this->GetName()) ); _prior->Reset(); cout << " Initializing flat Prior" << endl; //Initializing flat prior for(UInt_t ibin=0; ibin<_prior->GetNbinsX(); ibin++){ _prior->SetBinContent(ibin+1, _prior->GetBinWidth(ibin+1)/(_prior->GetBinLowEdge(_prior->GetNbinsX()+1)-_prior->GetBinLowEdge(1)) ); } cout << " Initializing Random number generator" << endl; rangen = new RanGen(); _bin_list = new TList(); _bin_hist_list = new TList(); _smearing_sample = (TH2D*) _smearing->Clone( Form("%s_sample", _smearing->GetName()) ); cout << " Initialization done" << endl; } void PamUnfold::NormalizeMatrix(){ for(UInt_t ibiny=0; ibiny<_smearing->GetNbinsY(); ibiny++){ for(UInt_t ibinx=0; ibinx<_smearing->GetNbinsX(); ibinx++){ Int_t globalbin = _smearing->GetBin(ibinx+1, ibiny+1); if(_norm->GetBinContent(ibinx+1)) _smearing->SetBinContent( globalbin, _smearing->GetBinContent(globalbin)/_norm->GetBinContent(ibinx+1) ); } } } void PamUnfold::SampleMatrix(){ _smearing_sample->Reset(); vector alpha(_smearing->GetNbinsY()+1); vector sampled; for(UInt_t ibinx=0; ibinx<_smearing->GetNbinsX(); ibinx++){ // cout << _norm->GetBinContent(ibinx+1) << endl; Double_t snorm=0; for(UInt_t ibiny=0; ibiny<_smearing->GetNbinsY(); ibiny++){ Int_t globalbin = _smearing->GetBin(ibinx+1, ibiny+1); snorm += _smearing->GetBinContent(globalbin); alpha[ibiny] = TMath::Nint( _smearing->GetBinContent(globalbin) * _norm->GetBinContent(ibinx+1) ); } alpha[_smearing->GetNbinsY()] = TMath::Nint( (1 - snorm) * _norm->GetBinContent(ibinx+1) ); //cout << "bin: " << ibinx << " " << alpha[_smearing->GetNbinsY()] << endl; sampled = rangen->Dirichlet(_smearing->GetNbinsY() + 1, alpha); for(UInt_t ibiny=0; ibiny<_smearing_sample->GetNbinsY(); ibiny++){ Int_t globalbin = _smearing_sample->GetBin(ibinx+1, ibiny+1); // cout << sampled[ibiny] << " "; _smearing_sample->SetBinContent(globalbin, sampled[ibiny]); } // cout << endl; } // cout << endl; } void PamUnfold::BuildFlux(){ _unfolded->Reset(); _bin_hist_list->Delete(); for(Int_t j=0; j<_unfolded->GetNbinsX(); j++){ Double_t min=1e9; Double_t max=0; Double_t check=0; for(Int_t i=0; i<_bin_list->GetEntries(); i++){ TVectorD* vv = (TVectorD*) _bin_list->At(i); check = (*vv)(j); if(checkmax) max=check; } _bin_hist_list->Add( new TH1D( Form("hh_%03i", j), ";Events", 150, min-20, max+20 ) ); } for(Int_t i=0; i<_bin_list->GetEntries(); i++){ TVectorD* vv = (TVectorD*) _bin_list->At(i); //cout << "Bin " << i << " "; for(Int_t j=0; jGetNoElements(); j++){ //cout << (*vv)(j) << " "; ((TH1D*) _bin_hist_list->At(j))->Fill( (*vv)(j) ); } // cout << endl; } Double_t qq = 0.682689492137; Double_t yq[2], xq[2]; xq[0] = (1-qq)/2; xq[1] = xq[0] + qq; for(Int_t j=0; j<_unfolded->GetNbinsX(); j++){ TH1D* mt = ((TH1D*) _bin_hist_list->At(j)); mt->GetQuantiles(2, yq, xq); double mean = 0.5*(yq[0] + yq[1]); double err = 0.5*(yq[1] - yq[0]); if(mt->ComputeIntegral()){ _unfolded->SetBinContent(j+1, mean); _unfolded->SetBinError(j+1, err); } else{ _unfolded->SetBinContent(j+1, 0); _unfolded->SetBinError(j+1, 0); } } } void PamUnfold::Draw(TString path){ Int_t nx, ny; FindSplitting(_unfolded->GetNbinsX() , nx, ny); canv = dynamic_cast(gDirectory->FindObject( Form("canv_%s", this->GetName()) )); if(!canv) canv = new TCanvas(Form("canv_%s", this->GetName()), "Bin Distributions", 0, 0, 4 + 500*nx, 28 + 500*ny); canv->Divide(nx, ny); for(Int_t ip=0; ip<_unfolded->GetNbinsX(); ip++){ canv->cd(ip+1); TH1D* mt = ((TH1D*) _bin_hist_list->At(ip)); mt->Draw(); Double_t mean = _unfolded->GetBinContent(ip+1); Double_t err = _unfolded->GetBinError(ip+1); TLine* line1 = new TLine(mean-err, 0, mean-err, mt->GetMaximum()); TLine* line2 = new TLine(mean+err, 0, mean+err, mt->GetMaximum()); TLine* line3 = new TLine(mean, 0, mean, mt->GetMaximum()); line1->SetLineWidth(2); line1->SetLineColor(2); line2->SetLineWidth(2); line2->SetLineColor(2); line3->SetLineWidth(2); line3->SetLineColor(4); line1->Draw("same"); line2->Draw("same"); line3->Draw("same"); } if(path) canv->Print(path); } void PamUnfold::FindSplitting(Int_t n, Int_t &nx, Int_t &ny){ Int_t x = TMath::Nint( sqrt(n) ); if(x*x == n){ nx=ny=x; return; } x = floor( sqrt(n) ) + 1; for(Int_t y=0; y<=x; y++){ if(y*x>=n){ ny = y; break;} } nx = x; if(ny>nx){ nx=ny; ny=x;} }