#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),
fXtau (NULL),
fXinv (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" );
}
fBcov = (TH2D*)fAdet->Clone("bcov");
for(int i=1; i<=fBdat->GetNbinsX(); i++){
fBcov->SetBinContent(i, i, fBdat->GetBinError(i)*fBdat->GetBinError(i));
for(int j=1; j<=fBdat->GetNbinsX(); j++){
if(i==j) continue;
fBcov->SetBinContent(i,j,0.);
}
}
fNdim = bdat->GetNbinsX();
fDdim = 2;
}
TSVDUnfold::TSVDUnfold( const TH1D *bdat, TH2D* Bcov, const TH1D *bini, const TH1D *xini, const TH2D *Adet )
: TObject (),
fNdim (0),
fDdim (2),
fNormalize (kFALSE),
fKReg (-1),
fDHist (NULL),
fSVHist (NULL),
fXtau (NULL),
fXinv (NULL),
fBdat (bdat),
fBcov (Bcov),
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() != Bcov->GetNbinsX() ||
bdat->GetNbinsX() != Bcov->GetNbinsY() ||
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(Bcov)=%i,%i\n", Bcov->GetNbinsX(), Bcov->GetNbinsY() );
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),
fXtau (other.fXtau),
fXinv (other.fXinv),
fBdat (other.fBdat),
fBcov (other.fBcov),
fBini (other.fBini),
fXini (other.fXini),
fAdet (other.fAdet),
fToyhisto (other.fToyhisto),
fToymat (other.fToymat),
fToyMode (other.fToyMode),
fMatToyMode (other.fMatToyMode)
{
}
TSVDUnfold::~TSVDUnfold()
{
if(fToyhisto){
delete fToyhisto;
fToyhisto = 0;
}
if(fToymat){
delete fToymat;
fToymat = 0;
}
if(fDHist){
delete fDHist;
fDHist = 0;
}
if(fSVHist){
delete fSVHist;
fSVHist = 0;
}
if(fXtau){
delete fXtau;
fXtau = 0;
}
if(fXinv){
delete fXinv;
fXinv = 0;
}
if(fBcov){
delete fBcov;
fBcov = 0;
}
}
TH1D* TSVDUnfold::Unfold( Int_t kreg )
{
fKReg = kreg;
if (!fToyMode && !fMatToyMode) InitHistos( );
TVectorD vb(fNdim), vbini(fNdim), vxini(fNdim), vberr(fNdim);
TMatrixD mB(fNdim, fNdim), 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 ); }
H2M( fBcov, mB);
H2V( fBini, vbini );
H2V( fXini, vxini );
if (fMatToyMode) H2M( fToymat, mA );
else H2M( fAdet, mA );
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;
TDecompSVD BSVD( mB );
TMatrixD QT = BSVD.GetU();
QT.Transpose(QT);
TVectorD B2SV = BSVD.GetSig();
TVectorD BSV(B2SV);
for(int i=0; i<fNdim; i++){
BSV(i) = TMath::Sqrt(B2SV(i));
}
TMatrixD mAtmp(fNdim,fNdim);
TVectorD vbtmp(fNdim);
mAtmp *= 0;
vbtmp *= 0;
for(int i=0; i<fNdim; i++){
for(int j=0; j<fNdim; j++){
if(BSV(i)){
vbtmp(i) += QT(i,j)*vb(j)/BSV(i);
}
for(int m=0; m<fNdim; m++){
if(BSV(i)){
mAtmp(i,j) += QT(i,m)*mA(m,j)/BSV(i);
}
}
}
}
mA = mAtmp;
vb = vbtmp;
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 vd = Uort*vb;
if (!fToyMode && !fMatToyMode) {
V2H(vd, *fDHist);
}
Int_t k = GetKReg()-1;
TVectorD vx(fNdim);
TVectorD vdz(fNdim);
TMatrixD Z(fNdim, 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));
Z(i,i) = vdz(i)*vdz(i);
}
TVectorD vz = CompProd( vd, vdz );
TMatrixD VortT(Vort);
VortT.Transpose(VortT);
TMatrixD W = mCinv*Vort*Z*VortT*mCinv;
TMatrixD Xtau(fNdim, fNdim);
TMatrixD Xinv(fNdim, fNdim);
Xtau *= 0;
Xinv *= 0;
for (Int_t i=0; i<fNdim; i++) {
for (Int_t j=0; j<fNdim; j++) {
Xtau(i,j) = vxini(i) * vxini(j) * W(i,j);
double a=0;
for (Int_t m=0; m<fNdim; m++) {
a += mA(m,i)*mA(m,j);
}
if(vxini(i)*vxini(j))
Xinv(i,j) = a/vxini(i)/vxini(j);
}
}
TVectorD vw = Vreg*vz;
vx = CompProd( vw, vxini );
if(fNormalize){
Double_t scale = vx.Sum();
if (scale > 0){
vx *= 1.0/scale;
Xtau *= 1./scale/scale;
Xinv *= scale*scale;
}
}
if (!fToyMode && !fMatToyMode) {
M2H(Xtau, *fXtau);
M2H(Xinv, *fXinv);
}
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");
unfcov->SetTitle("Toy covariance matrix");
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);
}
delete unfres;
unfres = 0;
}
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 unfres;
unfres = 0;
}
delete Lt;
delete toymean;
fToyMode = kFALSE;
return unfcov;
}
TH2D* TSVDUnfold::GetAdetCovMatrix( Int_t ntoys, Int_t seed )
{
fMatToyMode = true;
TH1D* unfres = 0;
TH2D* unfcov = (TH2D*)fAdet->Clone("unfcovmat");
unfcov->SetTitle("Toy covariance matrix");
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);
}
delete unfres;
unfres = 0;
}
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;
unfres = 0;
}
delete toymean;
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;
}
TH2D* TSVDUnfold::GetXtau() const
{
return fXtau;
}
TH2D* TSVDUnfold::GetXinv() const
{
return fXinv;
}
TH2D* TSVDUnfold::GetBCov() const
{
return fBcov;
}
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);
}
}
}
void TSVDUnfold::M2H( const TMatrixD& mat, TH2D& histo )
{
for (Int_t j=0; j<mat.GetNcols(); j++) {
for (Int_t i=0; i<mat.GetNrows(); i++) {
histo.SetBinContent(i+1,j+1, mat(i,j));
}
}
}
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();
fXtau = (TH2D*)fAdet->Clone("Xtau");
fXtau->SetTitle("Regularized covariance matrix");
fXtau->Sumw2();
fXinv = (TH2D*)fAdet->Clone("Xinv");
fXinv->SetTitle("Inverse covariance matrix");
fXinv->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)
{
UInt_t n = truspec.GetNbinsX();
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 )) * fXinv->GetBinContent(i+1,j+1) );
}
}
return chi2;
}