#include <iostream>
#include "TSVDUnfold.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TDecompSVD.h"
#include "TRandom3.h"
#include "TMath.h"
ClassImp(TSVDUnfold)
using namespace std;
TSVDUnfold::TSVDUnfold( const TH1D *bdat, const TH1D *bini, const TH1D *xini, const TH2D *Adet )
: TObject (),
fNdim (0),
fDdim (2),
fNormalize (kFALSE),
fKReg (-1),
fDHist (NULL),
fSVHist (NULL),
fBdat (bdat),
fBini (bini),
fXini (xini),
fAdet (Adet),
fToyhisto (NULL),
fToymat (NULL),
fToyMode (kFALSE),
fMatToyMode (kFALSE)
{
if (bdat->GetNbinsX() != bini->GetNbinsX() ||
bdat->GetNbinsX() != xini->GetNbinsX() ||
bdat->GetNbinsX() != Adet->GetNbinsX() ||
bdat->GetNbinsX() != Adet->GetNbinsY()) {
TString msg = "All histograms must have equal dimension.\n";
msg += Form( " Found: dim(bdat)=%i\n", bdat->GetNbinsX() );
msg += Form( " Found: dim(bini)=%i\n", bini->GetNbinsX() );
msg += Form( " Found: dim(xini)=%i\n", xini->GetNbinsX() );
msg += Form( " Found: dim(Adet)=%i,%i\n", Adet->GetNbinsX(), Adet->GetNbinsY() );
msg += "Please start again!";
Fatal( "Init", msg, "%s" );
}
fNdim = bdat->GetNbinsX();
fDdim = 2;
}
TSVDUnfold::TSVDUnfold( const TSVDUnfold& other )
: TObject ( other ),
fNdim (other.fNdim),
fDdim (other.fDdim),
fNormalize (other.fNormalize),
fKReg (other.fKReg),
fDHist (other.fDHist),
fSVHist (other.fSVHist),
fBdat (other.fBdat),
fBini (other.fBini),
fXini (other.fXini),
fAdet (other.fAdet),
fToyhisto (other.fToyhisto),
fToymat (other.fToymat),
fToyMode (other.fToyMode),
fMatToyMode (other.fMatToyMode)
{
}
TSVDUnfold::~TSVDUnfold()
{
}
TH1D* TSVDUnfold::Unfold( Int_t kreg )
{
fKReg = kreg;
if (!fToyMode && !fMatToyMode) InitHistos( );
TVectorD vb(fNdim), vbini(fNdim), vxini(fNdim), vberr(fNdim);
TMatrixD mA(fNdim, fNdim), mCurv(fNdim, fNdim), mC(fNdim, fNdim);
Double_t eps = 1e-12;
Double_t sreg;
if (fToyMode) { H2V( fToyhisto, vb ); H2Verr( fToyhisto, vberr ); }
else { H2V( fBdat, vb ); H2Verr( fBdat, vberr ); }
H2V( fBini, vbini );
H2V( fXini, vxini );
if (fMatToyMode) H2M( fToymat, mA );
else H2M( fAdet, mA );
Double_t scale = vb.Sum()/vbini.Sum();
vbini *= scale;
vxini *= scale;
mA *= scale;
FillCurvatureMatrix( mCurv, mC );
TDecompSVD CSVD(mC);
TMatrixD CUort = CSVD.GetU();
TMatrixD CVort = CSVD.GetV();
TVectorD CSV = CSVD.GetSig();
TMatrixD CSVM(fNdim, fNdim);
for (Int_t i=0; i<fNdim; i++) CSVM(i,i) = 1/CSV(i);
CUort.Transpose( CUort );
TMatrixD mCinv = (CVort*CSVM)*CUort;
vbini = VecDiv ( vbini, vberr );
vb = VecDiv ( vb, vberr, 1 );
mA = MatDivVec( mA, vberr, 1 );
vberr = VecDiv ( vberr, vberr, 1 );
TDecompSVD ASVD( mA*mCinv );
TMatrixD Uort = ASVD.GetU();
TMatrixD Vort = ASVD.GetV();
TVectorD ASV = ASVD.GetSig();
if (!fToyMode && !fMatToyMode) {
V2H(ASV, *fSVHist);
}
TMatrixD Vreg = mCinv*Vort;
Uort.Transpose(Uort);
TVectorD vdini = Uort*vbini;
TVectorD vd = Uort*vb;
if (!fToyMode && !fMatToyMode) {
V2H(vd, *fDHist);
}
Int_t k = GetKReg()-1;
TVectorD vx(fNdim);
TVectorD vdz(fNdim);
for (Int_t i=0; i<fNdim; i++) {
if (ASV(i)<ASV(0)*eps) sreg = ASV(0)*eps;
else sreg = ASV(i);
vdz(i) = sreg/(sreg*sreg + ASV(k)*ASV(k));
}
TVectorD vz = CompProd( vd, vdz );
TVectorD vw = Vreg*vz;
vx = CompProd( vw, vxini );
if(fNormalize){
scale = vx.Sum();
if (scale > 0) vx *= 1.0/scale;
}
if (!fToyMode && !fMatToyMode) {
Info( "Unfold", "Unfolding param: %i",k+1 );
Info( "Unfold", "Curvature of weight distribution: %f", GetCurvature( vw, mCurv ) );
}
TH1D* h = (TH1D*)fBdat->Clone("unfoldingresult");
for(int i=1; i<=fNdim; i++){
h->SetBinContent(i,0.);
h->SetBinError(i,0.);
}
V2H( vx, *h );
return h;
}
TH2D* TSVDUnfold::GetUnfoldCovMatrix( const TH2D* cov, Int_t ntoys, Int_t seed )
{
fToyMode = true;
TH1D* unfres = 0;
TH2D* unfcov = (TH2D*)fAdet->Clone("unfcovmat");
for(int i=1; i<=fNdim; i++)
for(int j=1; j<=fNdim; j++)
unfcov->SetBinContent(i,j,0.);
TMatrixD L(fNdim,fNdim); L *= 0;
for (Int_t iPar= 0; iPar < fNdim; iPar++) {
L(iPar,iPar) = cov->GetBinContent(iPar+1,iPar+1);
for (Int_t k=0; k<iPar; k++) L(iPar,iPar) -= TMath::Power( L(k,iPar), 2 );
if (L(iPar,iPar) > 0.0) L(iPar,iPar) = TMath::Sqrt(L(iPar,iPar));
else L(iPar,iPar) = 0.0;
for (Int_t jPar=iPar+1; jPar<fNdim; jPar++) {
L(iPar,jPar) = cov->GetBinContent(iPar+1,jPar+1);
for (Int_t k=0; k<iPar; k++) L(iPar,jPar) -= L(k,iPar)*L(k,jPar);
if (L(iPar,iPar)!=0.) L(iPar,jPar) /= L(iPar,iPar);
else L(iPar,jPar) = 0;
}
}
TMatrixD *Lt = new TMatrixD(TMatrixD::kTransposed,L);
TRandom3 random(seed);
fToyhisto = (TH1D*)fBdat->Clone("toyhisto");
TH1D *toymean = (TH1D*)fBdat->Clone("toymean");
for (Int_t j=1; j<=fNdim; j++) toymean->SetBinContent(j,0.);
for (int i=1; i<=ntoys; i++) {
TVectorD g(fNdim);
for (Int_t k= 0; k < fNdim; k++) g(k) = random.Gaus(0.,1.);
g *= (*Lt);
for (int j=1; j<=fNdim; j++) {
fToyhisto->SetBinContent(j,fBdat->GetBinContent(j)+g(j-1));
fToyhisto->SetBinError(j,fBdat->GetBinError(j));
}
unfres = Unfold(GetKReg());
for (Int_t j=1; j<=fNdim; j++) {
toymean->SetBinContent(j, toymean->GetBinContent(j) + unfres->GetBinContent(j)/ntoys);
}
}
random.SetSeed(seed);
for (int i=1; i<=ntoys; i++) {
TVectorD g(fNdim);
for (Int_t k= 0; k < fNdim; k++) g(k) = random.Gaus(0.,1.);
g *= (*Lt);
for (int j=1; j<=fNdim; j++) {
fToyhisto->SetBinContent( j, fBdat->GetBinContent(j)+g(j-1) );
fToyhisto->SetBinError ( j, fBdat->GetBinError(j) );
}
unfres = Unfold(GetKReg());
for (Int_t j=1; j<=fNdim; j++) {
for (Int_t k=1; k<=fNdim; k++) {
unfcov->SetBinContent(j,k,unfcov->GetBinContent(j,k) + ( (unfres->GetBinContent(j) - toymean->GetBinContent(j))* (unfres->GetBinContent(k) - toymean->GetBinContent(k))/(ntoys-1)) );
}
}
}
delete Lt;
delete unfres;
fToyMode = kFALSE;
return unfcov;
}
TH2D* TSVDUnfold::GetAdetCovMatrix( Int_t ntoys, Int_t seed )
{
fMatToyMode = true;
TH1D* unfres = 0;
TH2D* unfcov = (TH2D*)fAdet->Clone("unfcovmat");
for(int i=1; i<=fNdim; i++)
for(int j=1; j<=fNdim; j++)
unfcov->SetBinContent(i,j,0.);
TRandom3 random(seed);
fToymat = (TH2D*)fAdet->Clone("toymat");
TH1D *toymean = (TH1D*)fXini->Clone("toymean");
for (Int_t j=1; j<=fNdim; j++) toymean->SetBinContent(j,0.);
for (int i=1; i<=ntoys; i++) {
for (Int_t k=1; k<=fNdim; k++) {
for (Int_t m=1; m<=fNdim; m++) {
if (fAdet->GetBinContent(k,m)) {
fToymat->SetBinContent(k, m, random.Poisson(fAdet->GetBinContent(k,m)));
}
}
}
unfres = Unfold(GetKReg());
for (Int_t j=1; j<=fNdim; j++) {
toymean->SetBinContent(j, toymean->GetBinContent(j) + unfres->GetBinContent(j)/ntoys);
}
}
random.SetSeed(seed);
for (int i=1; i<=ntoys; i++) {
for (Int_t k=1; k<=fNdim; k++) {
for (Int_t m=1; m<=fNdim; m++) {
if (fAdet->GetBinContent(k,m))
fToymat->SetBinContent(k, m, random.Poisson(fAdet->GetBinContent(k,m)));
}
}
unfres = Unfold(GetKReg());
for (Int_t j=1; j<=fNdim; j++) {
for (Int_t k=1; k<=fNdim; k++) {
unfcov->SetBinContent(j,k,unfcov->GetBinContent(j,k) + ( (unfres->GetBinContent(j) - toymean->GetBinContent(j))*(unfres->GetBinContent(k) - toymean->GetBinContent(k))/(ntoys-1)) );
}
}
}
delete unfres;
fMatToyMode = kFALSE;
return unfcov;
}
TH1D* TSVDUnfold::GetD() const
{
for (int i=1; i<=fDHist->GetNbinsX(); i++) {
if (fDHist->GetBinContent(i)<0.) fDHist->SetBinContent(i, TMath::Abs(fDHist->GetBinContent(i)));
}
return fDHist;
}
TH1D* TSVDUnfold::GetSV() const
{
return fSVHist;
}
void TSVDUnfold::H2V( const TH1D* histo, TVectorD& vec )
{
for (Int_t i=0; i<histo->GetNbinsX(); i++) vec(i) = histo->GetBinContent(i+1);
}
void TSVDUnfold::H2Verr( const TH1D* histo, TVectorD& vec )
{
for (Int_t i=0; i<histo->GetNbinsX(); i++) vec(i) = histo->GetBinError(i+1);
}
void TSVDUnfold::V2H( const TVectorD& vec, TH1D& histo )
{
for(Int_t i=0; i<vec.GetNrows(); i++) histo.SetBinContent(i+1, vec(i));
}
void TSVDUnfold::H2M( const TH2D* histo, TMatrixD& mat )
{
for (Int_t j=0; j<histo->GetNbinsX(); j++) {
for (Int_t i=0; i<histo->GetNbinsY(); i++) {
mat(i,j) = histo->GetBinContent(i+1,j+1);
}
}
}
TVectorD TSVDUnfold::VecDiv( const TVectorD& vec1, const TVectorD& vec2, Int_t zero )
{
TVectorD quot(vec1.GetNrows());
for (Int_t i=0; i<vec1.GetNrows(); i++) {
if (vec2(i) != 0) quot(i) = vec1(i) / vec2(i);
else {
if (zero) quot(i) = 0;
else quot(i) = vec1(i);
}
}
return quot;
}
TMatrixD TSVDUnfold::MatDivVec( const TMatrixD& mat, const TVectorD& vec, Int_t zero )
{
TMatrixD quotmat(mat.GetNrows(), mat.GetNcols());
for (Int_t i=0; i<mat.GetNrows(); i++) {
for (Int_t j=0; j<mat.GetNcols(); j++) {
if (vec(i) != 0) quotmat(i,j) = mat(i,j) / vec(i);
else {
if (zero) quotmat(i,j) = 0;
else quotmat(i,j) = mat(i,j);
}
}
}
return quotmat;
}
TVectorD TSVDUnfold::CompProd( const TVectorD& vec1, const TVectorD& vec2 )
{
TVectorD res(vec1.GetNrows());
for (Int_t i=0; i<vec1.GetNrows(); i++) res(i) = vec1(i) * vec2(i);
return res;
}
Double_t TSVDUnfold::GetCurvature(const TVectorD& vec, const TMatrixD& curv)
{
return vec*(curv*vec);
}
void TSVDUnfold::FillCurvatureMatrix( TMatrixD& tCurv, TMatrixD& tC ) const
{
Double_t eps = 0.00001;
Int_t ndim = tCurv.GetNrows();
tCurv *= 0;
tC *= 0;
if (fDdim == 0) for (Int_t i=0; i<ndim; i++) tC(i,i) = 1;
else if (ndim == 1) {
for (Int_t i=0; i<ndim; i++) {
if (i < ndim-1) tC(i,i+1) = 1.0;
tC(i,i) = 1.0;
}
}
else if (fDdim == 2) {
for (Int_t i=0; i<ndim; i++) {
if (i > 0) tC(i,i-1) = 1.0;
if (i < ndim-1) tC(i,i+1) = 1.0;
tC(i,i) = -2.0;
}
tC(0,0) = -1.0;
tC(ndim-1,ndim-1) = -1.0;
}
else if (fDdim == 3) {
for (Int_t i=1; i<ndim-2; i++) {
tC(i,i-1) = 1.0;
tC(i,i) = -3.0;
tC(i,i+1) = 3.0;
tC(i,i+2) = -1.0;
}
}
else if (fDdim==4) {
for (Int_t i=0; i<ndim; i++) {
if (i > 0) tC(i,i-1) = -4.0;
if (i < ndim-1) tC(i,i+1) = -4.0;
if (i > 1) tC(i,i-2) = 1.0;
if (i < ndim-2) tC(i,i+2) = 1.0;
tC(i,i) = 6.0;
}
tC(0,0) = 2.0;
tC(ndim-1,ndim-1) = 2.0;
tC(0,1) = -3.0;
tC(ndim-2,ndim-1) = -3.0;
tC(1,0) = -3.0;
tC(ndim-1,ndim-2) = -3.0;
tC(1,1) = 6.0;
tC(ndim-2,ndim-2) = 6.0;
}
else if (fDdim == 5) {
for (Int_t i=2; i < ndim-3; i++) {
tC(i,i-2) = 1.0;
tC(i,i-1) = -5.0;
tC(i,i) = 10.0;
tC(i,i+1) = -10.0;
tC(i,i+2) = 5.0;
tC(i,i+3) = -1.0;
}
}
else if (fDdim == 6) {
for (Int_t i = 3; i < ndim - 3; i++) {
tC(i,i-3) = 1.0;
tC(i,i-2) = -6.0;
tC(i,i-1) = 15.0;
tC(i,i) = -20.0;
tC(i,i+1) = 15.0;
tC(i,i+2) = -6.0;
tC(i,i+3) = 1.0;
}
}
for (Int_t i=0; i<ndim; i++) tC(i,i) = tC(i,i) + eps;
for (Int_t i=0; i<ndim; i++) {
for (Int_t j=0; j<ndim; j++) {
for (Int_t k=0; k<ndim; k++) {
tCurv(i,j) = tCurv(i,j) + tC(k,i)*tC(k,j);
}
}
}
}
void TSVDUnfold::InitHistos( )
{
fDHist = new TH1D( "dd", "d vector after orthogonal transformation", fNdim, 0, fNdim );
fDHist->Sumw2();
fSVHist = new TH1D( "sv", "Singular values of AC^-1", fNdim, 0, fNdim );
fSVHist->Sumw2();
}
void TSVDUnfold::RegularisedSymMatInvert( TMatrixDSym& mat, Double_t eps )
{
const UInt_t n = mat.GetNrows();
UInt_t nn = 0;
UInt_t *ipos = new UInt_t[n];
Double_t ymax = 0;
for (UInt_t i=0; i<n; i++) if (TMath::Abs(mat[i][i]) > ymax) ymax = TMath::Abs(mat[i][i]);
for (UInt_t i=0; i<n; i++) {
if (TMath::Abs(mat[i][i])/ymax > eps) ipos[nn++] = i;
}
TMatrixDSym matwork( nn );
for (UInt_t in=0; in<nn; in++) for (UInt_t jn=0; jn<nn; jn++) matwork(in,jn) = 0;
for (UInt_t in=0; in<nn; in++) {
matwork[in][in] = mat[ipos[in]][ipos[in]];
for (UInt_t jn=in+1; jn<nn; jn++) {
matwork[in][jn] = mat[ipos[in]][ipos[jn]];
matwork[jn][in] = matwork[in][jn];
}
}
matwork.Invert();
for (UInt_t i=0; i<n; i++) for (UInt_t j=0; j<n; j++) mat[i][j] = 0;
for (UInt_t in=0; in<nn; in++) {
mat[ipos[in]][ipos[in]] = matwork[in][in];
for (UInt_t jn=in+1; jn<nn; jn++) {
mat[ipos[in]][ipos[jn]] = matwork[in][jn];
mat[ipos[jn]][ipos[in]] = mat[ipos[in]][ipos[jn]];
}
}
delete [] ipos;
}
Double_t TSVDUnfold::ComputeChiSquared( const TH1D& truspec, const TH1D& unfspec, const TH2D& covmat, Double_t regpar )
{
UInt_t n = truspec.GetNbinsX();
TMatrixDSym mat( n );
for (UInt_t i=0; i<n; i++) {
for (UInt_t j=i; j<n; j++) {
mat[i][j] = covmat.GetBinContent( i+1, j+1 );
mat[j][i] = mat[i][j];
}
}
RegularisedSymMatInvert( mat, regpar );
Double_t chi2 = 0;
for (UInt_t i=0; i<n; i++) {
for (UInt_t j=0; j<n; j++) {
chi2 += ( (truspec.GetBinContent( i+1 )-unfspec.GetBinContent( i+1 )) *
(truspec.GetBinContent( j+1 )-unfspec.GetBinContent( j+1 )) * mat[i][j] );
}
}
return chi2;
}