/************************************************************************** * Copyright(c) 2006-07, ALICE Experiment at CERN, All rights reserved. * * * * Author: The ALICE Off-line Project. * * Contributors are mentioned in the code where appropriate. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /* $Id$ */ //------------------------------------------------------------------------- // Implementation of the AliSplineFit class // The class performs a spline fit on an incoming TGraph. The graph is // divided into several parts (identified by knots between each part). // Spline fits are performed on each part. According to user parameters, // the function, first and second derivative are requested to be continuous // at each knot. // Origin: Marian Ivanov, CERN, Marian.Ivanov@cern.ch // Adjustments by Haavard Helstrup, Haavard.Helstrup@cern.ch //------------------------------------------------------------------------- #include #include "AliSplineFit.h" ClassImp(AliSplineFit) TLinearFitter* AliSplineFit::fitterStatic() { static TLinearFitter* fit = new TLinearFitter(4,"pol3",""); return fit; } AliSplineFit::AliSplineFit() : fBDump(kFALSE), fGraph (0), fNmin (0), fSigma (0), fMaxDelta (0), fN0 (0), fParams (0), fCovars (0), fIndex (0), fN (0), fChi2 (0.0), fX (0), fY0 (0), fY1 (0), fChi2I (0) // // Default constructor // { } AliSplineFit::AliSplineFit(const AliSplineFit& source) : TObject(source), fBDump (source.fBDump), fGraph (source.fGraph), fNmin (source.fNmin), fSigma (source.fSigma), fMaxDelta (source.fMaxDelta), fN0 (source.fN0), fN (source.fN), fChi2 (source.fChi2) { // // Copy constructor // fIndex = new Int_t[fN0]; fParams = new TClonesArray("TVectorD",fN0); fCovars = new TClonesArray("TMatrixD",fN0); fParams = (TClonesArray*)source.fParams->Clone(); fCovars = (TClonesArray*)source.fCovars->Clone(); for (Int_t i=0; ifN-2) index =fN-2; // Double_t dx = x-fX[index]; Double_t dxc = fX[index+1]-fX[index]; Double_t y0 = fY0[index]; Double_t y1 = fY1[index]; Double_t y01 = fY0[index+1]; Double_t y11 = fY1[index+1]; Double_t y2 = -(3.*y0-3.*y01+2*y1*dxc+y11*dxc)/(dxc*dxc); Double_t y3 = -(-2.* y0 + 2*y01 - y1*dxc - y11*dxc) /(dxc*dxc*dxc); Double_t val = y0+y1*dx+y2*dx*dx+y3*dx*dx*dx; if (deriv==1) val = y1+2.*y2*dx+3.*y3*dx*dx; if (deriv==2) val = 2.*y2+6.*y3*dx; if (deriv==3) val = 6*y3; return val; } TGraph * AliSplineFit::GenerGraph(Int_t npoints, Double_t fraction, Double_t s1, Double_t s2, Double_t s3, Int_t der){ // // generate random graph // xrange 0,1 // yrange 0,1 // s1, s2, s3 - sigma of derivative // fraction - Double_t *value = new Double_t[npoints]; Double_t *time = new Double_t[npoints]; Double_t d0=0, d1=0,d2=0,d3=0; value[0] = d0; time[0] = 0; for(Int_t i=1; iExp(s1))*(gRandom->Rndm()-0.5); d2 =(1.-fraction)*d2+fraction*(gRandom->Exp(s2))*(gRandom->Rndm()-0.5); d3 =(1.-fraction)*d3+fraction*(gRandom->Exp(s3))*(gRandom->Rndm()-0.5); if (gRandom->Rndm()BreitWigner(0,s3)); } Double_t dmean = (value[npoints-1]-value[0])/(time[npoints-1]-time[0]); Double_t min = value[0]; Double_t max = value[0]; for (Int_t i=0; imax) max=value[i]; } for (Int_t i=0; iGetN(); Double_t *value = new Double_t[npoints]; Double_t *time = new Double_t[npoints]; for(Int_t i=0; iGetX()[i]; value[i] = graph0->GetY()[i]+gRandom->Gaus(0,sigma0); } TGraph * graph = new TGraph(npoints,time,value); delete [] value; delete [] time; return graph; } TGraph * AliSplineFit::MakeGraph(Double_t xmin, Double_t xmax, Int_t npoints, Int_t deriv) const { // // if npoints<=0 draw derivative // TGraph *graph =0; if (npoints<=0) { if (deriv<=0) return new TGraph(fN,fX,fY0); if (deriv==1) return new TGraph(fN,fX,fY1); if (deriv>2) return new TGraph(fN-1,fX,fChi2I); } Double_t * x = new Double_t[npoints+1]; Double_t * y = new Double_t[npoints+1]; for (Int_t ip=0; ip<=npoints; ip++){ x[ip] = xmin+ (xmax-xmin)*(Double_t(ip)/Double_t(npoints)); y[ip] = Eval(x[ip],deriv); } graph = new TGraph(npoints,x,y); delete [] x; delete [] y; return graph; } TGraph * AliSplineFit::MakeDiff(TGraph * graph0) const { // // Make graph of difference to reference graph // Int_t npoints=graph0->GetN(); TGraph *graph =0; Double_t * x = new Double_t[npoints]; Double_t * y = new Double_t[npoints]; for (Int_t ip=0; ipGetX()[ip]; y[ip] = Eval(x[ip],0)-graph0->GetY()[ip]; } graph = new TGraph(npoints,x,y); delete [] x; delete [] y; return graph; } TH1F * AliSplineFit::MakeDiffHisto(TGraph * graph0) const { // // Make histogram of difference to reference graph // Int_t npoints=graph0->GetN(); Float_t min=1e+39,max=-1e+39; for (Int_t ip=0; ipGetX()[ip]; Double_t y = Eval(x,0)-graph0->GetY()[ip]; if (ip==0) { min = y; max = y; }else{ if (ymax) max=y; } } TH1F *his = new TH1F("hdiff","hdiff", 100, min, max); for (Int_t ip=0; ipGetX()[ip]; Double_t y = Eval(x,0)-graph0->GetY()[ip]; his->Fill(y); } return his; } void AliSplineFit::InitKnots(TGraph * graph, Int_t min, Int_t iter, Double_t maxDelta){ // // initialize knots + estimate sigma of noise + make initial parameters // // const Double_t kEpsilon = 1.e-7; fGraph = graph; fNmin = min; fMaxDelta = maxDelta; Int_t npoints = fGraph->GetN(); fN0 = (npoints/fNmin)+1; Float_t delta = Double_t(npoints)/Double_t(fN0-1); fParams = new TClonesArray("TVectorD",fN0); fCovars = new TClonesArray("TMatrixD",fN0); fIndex = new Int_t[fN0]; TLinearFitter fitterLocal(4,"pol3"); // local fitter Double_t sigma2 =0; Double_t yMin=graph->GetY()[0]; Double_t yMax=graph->GetY()[0]; for (Int_t iKnot=0; iKnot0) ? fIndex[iKnot-1]:index0; fIndex[iKnot]=TMath::Min(index0, npoints-1); Float_t startX =graph->GetX()[fIndex[iKnot]]; for (Int_t ipoint=indexM; ipointGetX()[ipoint]-startX; Double_t y = graph->GetY()[ipoint]; if (yyMax) yMax=y; fitterLocal.AddPoint(&dxl,y,1); } fitterLocal.Eval(); sigma2 += fitterLocal.GetChisquare()/Double_t((index1-indexM)-4.); TMatrixD * covar = new ((*fCovars)[iKnot]) TMatrixD(4,4); TVectorD * param = new ((*fParams)[iKnot]) TVectorD(4); fitterLocal.GetParameters(*param); fitterLocal.GetCovarianceMatrix(*covar); fitterLocal.ClearPoints(); } fSigma =TMath::Sqrt(sigma2/Double_t(fN0)); // mean sigma Double_t tDiff = ((yMax-yMin)+TMath::Abs(yMax)+TMath::Abs(yMin))*kEpsilon; fSigma += tDiff+fMaxDelta/TMath::Sqrt(npoints); fMaxDelta +=tDiff; for (Int_t iKnot=0; iKnotAt(iKnot)); cov*=fSigma*fSigma; } OptimizeKnots(iter); fN = 0; for (Int_t iKnot=0; iKnot=0) fN++; fX = new Double_t[fN]; fY0 = new Double_t[fN]; fY1 = new Double_t[fN]; fChi2I = new Double_t[fN]; Int_t iKnot=0; for (Int_t i=0; i=fN) { printf("AliSplineFit::InitKnots: Knot number > Max knot number\n"); break; } TVectorD * param = (TVectorD*) fParams->At(i); fX[iKnot] = fGraph->GetX()[fIndex[i]]; fY0[iKnot] = (*param)(0); fY1[iKnot] = (*param)(1); fChi2I[iKnot] = 0; iKnot++; } } Int_t AliSplineFit::OptimizeKnots(Int_t nIter){ // // // const Double_t kMaxChi2= 5; Int_t nKnots=0; TTreeSRedirector cstream("SplineIter.root"); for (Int_t iIter=0; iIterGetX()[fIndex[iKnot]]; if (fBDump) { TMatrixD * covar = (TMatrixD*)fCovars->At(iKnot); TVectorD * param = (TVectorD*)fParams->At(iKnot); cstream<<"Chi2"<< "iIter="<kMaxChi2) { nKnots++;continue;} fIndex[iKnot]*=-1; Int_t iPrevious=iKnot-1; Int_t iNext =iKnot+1; while (fIndex[iPrevious]<0) iPrevious--; while (fIndex[iNext]<0) iNext++; RefitKnot(iPrevious); RefitKnot(iNext); iKnot++; while (iKnot0) ?iKnot-1: 0; Int_t iNext =(iKnot0&&fIndex[iPrevious]<0) iPrevious--; while (iNext=fN0) iNext=fN0-1; Double_t startX = fGraph->GetX()[fIndex[iKnot]]; AliSplineFit::fitterStatic()->ClearPoints(); Int_t indPrev = fIndex[iPrevious]; Int_t indNext = fIndex[iNext]; Double_t *graphX = fGraph->GetX(); Double_t *graphY = fGraph->GetY(); // make arrays for points to fit (to save time) Int_t nPoints = indNext-indPrev; Double_t *xPoint = new Double_t[3*nPoints]; Double_t *yPoint = &xPoint[nPoints]; Double_t *ePoint = &xPoint[2*nPoints]; Int_t indVec=0; for (Int_t iPoint=indPrev; iPointAssignData(nPoints,1,xPoint,yPoint,ePoint); AliSplineFit::fitterStatic()->Eval(); // delete temporary arrays delete [] xPoint; TMatrixD * covar = (TMatrixD*)fCovars->At(iKnot); TVectorD * param = (TVectorD*)fParams->At(iKnot); AliSplineFit::fitterStatic()->GetParameters(*param); AliSplineFit::fitterStatic()->GetCovarianceMatrix(*covar); return 0; } Float_t AliSplineFit::CheckKnot(Int_t iKnot){ // // // Int_t iPrevious=iKnot-1; Int_t iNext =iKnot+1; while (fIndex[iPrevious]<0) iPrevious--; while (fIndex[iNext]<0) iNext++; TVectorD &pPrevious = *((TVectorD*)fParams->At(iPrevious)); TVectorD &pNext = *((TVectorD*)fParams->At(iNext)); TVectorD &pKnot = *((TVectorD*)fParams->At(iKnot)); TMatrixD &cPrevious = *((TMatrixD*)fCovars->At(iPrevious)); TMatrixD &cNext = *((TMatrixD*)fCovars->At(iNext)); TMatrixD &cKnot = *((TMatrixD*)fCovars->At(iKnot)); Double_t xPrevious = fGraph->GetX()[fIndex[iPrevious]]; Double_t xNext = fGraph->GetX()[fIndex[iNext]]; Double_t xKnot = fGraph->GetX()[fIndex[iKnot]]; // extra variables introduced to save processing time Double_t dxc = xNext-xPrevious; Double_t invDxc = 1./dxc; Double_t invDxc2 = invDxc*invDxc; TMatrixD tPrevious(4,4); TMatrixD tNext(4,4); tPrevious(0,0) = 1; tPrevious(1,1) = 1; tPrevious(2,0) = -3.*invDxc2; tPrevious(2,1) = -2.*invDxc; tPrevious(3,0) = 2.*invDxc2*invDxc; tPrevious(3,1) = 1.*invDxc2; tNext(2,0) = 3.*invDxc2; tNext(2,1) = -1*invDxc; tNext(3,0) = -2.*invDxc2*invDxc; tNext(3,1) = 1.*invDxc2; TMatrixD tpKnot(4,4); TMatrixD tpNext(4,4); Double_t dx = xKnot-xPrevious; tpKnot(0,0) = 1; tpKnot(1,1) = 1; tpKnot(2,2) = 1; tpKnot(3,3) = 1; tpKnot(0,1) = dx; tpKnot(0,2) = dx*dx; tpKnot(0,3) = dx*dx*dx; tpKnot(1,2) = 2.*dx; tpKnot(1,3) = 3.*dx*dx; tpKnot(2,3) = 3.*dx; Double_t dxn = xNext-xPrevious; tpNext(0,0) = 1; tpNext(1,1) = 1; tpNext(2,2) = 1; tpNext(3,3) = 1; tpNext(0,1) = dxn; tpNext(0,2) = dxn*dxn; tpNext(0,3) = dxn*dxn*dxn; tpNext(1,2) = 2.*dxn; tpNext(1,3) = 3.*dxn*dxn; tpNext(2,3) = 3.*dxn; // // matrix and vector at previous // TVectorD sPrevious = tPrevious*pPrevious+tNext*pNext; TVectorD sKnot = tpKnot*sPrevious; TVectorD sNext = tpNext*sPrevious; TMatrixD csPrevious00(tPrevious, TMatrixD::kMult,cPrevious); csPrevious00 *= tPrevious.T(); TMatrixD csPrevious01(tNext,TMatrixD::kMult,cNext); csPrevious01*=tNext.T(); TMatrixD csPrevious(csPrevious00,TMatrixD::kPlus,csPrevious01); TMatrixD csKnot(tpKnot,TMatrixD::kMult,csPrevious); csKnot*=tpKnot.T(); TMatrixD csNext(tpNext,TMatrixD::kMult,csPrevious); csNext*=tpNext.T(); TVectorD dPrevious = pPrevious-sPrevious; TVectorD dKnot = pKnot-sKnot; TVectorD dNext = pNext-sNext; // // TMatrixD prec(4,4); prec(0,0) = (fMaxDelta*fMaxDelta); prec(1,1) = prec(0,0)*invDxc2; prec(2,2) = prec(1,1)*invDxc2; prec(3,3) = prec(2,2)*invDxc2; // prec(0,0) = (fMaxDelta*fMaxDelta); // prec(1,1) = (fMaxDelta*fMaxDelta)/(dxc*dxc); // prec(2,2) = (fMaxDelta*fMaxDelta)/(dxc*dxc*dxc*dxc); // prec(3,3) = (fMaxDelta*fMaxDelta)/(dxc*dxc*dxc*dxc*dxc*dxc); csPrevious+=cPrevious; csPrevious+=prec; csPrevious.Invert(); Double_t chi2P = dPrevious*(csPrevious*dPrevious); csKnot+=cKnot; csKnot+=prec; csKnot.Invert(); Double_t chi2K = dKnot*(csKnot*dKnot); csNext+=cNext; csNext+=prec; csNext.Invert(); Double_t chi2N = dNext*(csNext*dNext); return (chi2P+chi2K+chi2N)/8.; } void AliSplineFit::SplineFit(Int_t nder){ // // Cubic spline fit of graph // // nder // nder<0 - no continuity requirement // =0 - continous 0 derivative // =1 - continous 1 derivative // >1 - continous 2 derivative // if (!fGraph) return; TGraph * graph = fGraph; if (nder>1) nder=2; Int_t nknots = fN; Int_t npoints = graph->GetN(); // // // spline fit // each knot 4 parameters // TMatrixD *pmatrix = 0; TVectorD *pvalues = 0; if (nder>1){ pmatrix = new TMatrixD(4*(nknots-1)+3*(nknots-2), 4*(nknots-1)+3*(nknots-2)); pvalues = new TVectorD(4*(nknots-1)+3*(nknots-2)); } if (nder==1){ pmatrix = new TMatrixD(4*(nknots-1)+2*(nknots-2), 4*(nknots-1)+2*(nknots-2)); pvalues = new TVectorD(4*(nknots-1)+2*(nknots-2)); } if (nder==0){ pmatrix = new TMatrixD(4*(nknots-1)+1*(nknots-2), 4*(nknots-1)+1*(nknots-2)); pvalues = new TVectorD(4*(nknots-1)+1*(nknots-2)); } if (nder<0){ pmatrix = new TMatrixD(4*(nknots-1)+0*(nknots-2), 4*(nknots-1)+0*(nknots-2)); pvalues = new TVectorD(4*(nknots-1)+0*(nknots-2)); } TMatrixD &matrix = *pmatrix; TVectorD &values = *pvalues; Int_t current = 0; // // defined extra variables (current4 etc.) to save processing time. // fill normal matrices, then copy to sparse matrix. // Double_t *graphX = graph->GetX(); Double_t *graphY = graph->GetY(); for (Int_t ip=0;ipfX[current+1]) current++; Double_t xmiddle = (fX[current+1]+fX[current])*0.5; Double_t x1 = graphX[ip]- xmiddle; Double_t x2 = x1*x1; Double_t x3 = x2*x1; Double_t x4 = x2*x2; Double_t x5 = x3*x2; Double_t x6 = x3*x3; Double_t y = graphY[ip]; Int_t current4 = 4*current; matrix(current4 , current4 )+=1; matrix(current4 , current4+1)+=x1; matrix(current4 , current4+2)+=x2; matrix(current4 , current4+3)+=x3; // matrix(current4+1, current4 )+=x1; matrix(current4+1, current4+1)+=x2; matrix(current4+1, current4+2)+=x3; matrix(current4+1, current4+3)+=x4; // matrix(current4+2, current4 )+=x2; matrix(current4+2, current4+1)+=x3; matrix(current4+2, current4+2)+=x4; matrix(current4+2, current4+3)+=x5; // matrix(current4+3, current4 )+=x3; matrix(current4+3, current4+1)+=x4; matrix(current4+3, current4+2)+=x5; matrix(current4+3, current4+3)+=x6; // values(current4 ) += y; values(current4+1) += y*x1; values(current4+2) += y*x2; values(current4+3) += y*x3; } // // constraint 0 // Int_t offset =4*(nknots-1)-1; if (nder>=0) for (Int_t iknot = 1; iknot=1)for (Int_t iknot = 1; iknot=2) for (Int_t iknot = 1; iknotGetN(); Double_t *xknots = new Double_t[npoints]; Int_t nknots =0; Int_t ipoints =0; // // generate knots // for (Int_t ip=0;ipGetX()[ip]-xknots[nknots-1]>maxdelta && ipoints>minpoints){ xknots[nknots] = graph->GetX()[ip]; ipoints=1; nknots++; } ipoints++; } if (npoints-ipoints>minpoints){ xknots[nknots] = graph->GetX()[npoints-1]; nknots++; }else{ xknots[nknots-1] = graph->GetX()[npoints-1]; } fN = nknots; fX = new Double_t[nknots]; fY0 = new Double_t[nknots]; fY1 = new Double_t[nknots]; fChi2I= new Double_t[nknots]; for (Int_t i=0; iGetN()*ratio); TGraph * graphT0 = smooth.SmoothKern(graph,type,ratio); if (!graphT0) return; TGraph graphT1(npoints2); for (Int_t ipoint=0; ipointGetN()-1; graphT1.SetPoint(ipoint, graphT0->GetX()[pointS] , graphT0->GetY()[pointS]); } TSpline3 spline2("spline", &graphT1); Update(&spline2, npoints2); } void AliSplineFit::Update(TSpline3 *spline, Int_t nknots){ // // // fN = nknots; fX = new Double_t[nknots]; fY0 = new Double_t[nknots]; fY1 = new Double_t[nknots]; Double_t d0, d1; fChi2I= 0; for (Int_t i=0; iGetCoeff(i,fX[i],fY0[i], fY1[i],d0,d1); } } void AliSplineFit::Test(Int_t npoints, Int_t ntracks, Float_t snoise){ // // test function // AliSplineFit fit; AliSplineFit fitS; TGraph * graph0=0; TGraph * graph1=0; TTreeSRedirector *pcstream = new TTreeSRedirector("TestSmooth.root"); for (Int_t i=0; iGetMean(); Double_t sigma2 = h2->GetRMS(); Double_t mean1 = h1->GetMean(); Double_t sigma1 = h1->GetRMS(); Double_t meanS = hS->GetMean(); Double_t sigmaS = hS->GetRMS(); char fname[100]; if (fit.fN<20){ sprintf(fname,"pol%d",fit.fN); }else{ sprintf(fname,"pol%d",19); } TF1 fpol("fpol",fname); graph1->Fit(&fpol); TGraph dpol(*graph1); TGraph gpol(*graph1); for (Int_t ipoint=0; ipointGetN(); ipoint++){ dpol.GetY()[ipoint]= graph0->GetY()[ipoint]- fpol.Eval(graph0->GetX()[ipoint]); gpol.GetY()[ipoint]= fpol.Eval(graph0->GetX()[ipoint]); } (*pcstream)<<"Test"<< "Event="<