/************************************************************************** * 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. * **************************************************************************/ //------------------------------------------------------------------------- // 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 "AliSplineFit.h" ClassImp(AliSplineFit) TLinearFitter* AliSplineFit::fitterStatic() { static TLinearFitter* fit = new TLinearFitter(4,"pol3",""); return fit; } AliSplineFit::AliSplineFit() : fBDump(kFALSE), fGraph (0), fNmin (0), fMinPoints(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), fMinPoints (source.fMinPoints), fSigma (source.fSigma), fMaxDelta (source.fMaxDelta), fN0 (source.fN0), fParams (0), fCovars (0), fIndex (0), fN (source.fN), fChi2 (0.0), fX (0), fY0 (0), fY1 (0), fChi2I (source.fChi2I) { // // 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]; if (dxc<=0) return fY0[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(); // Make simple spline if too few points in graph if (npoints < fMinPoints ) { CopyGraph(); return; } 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; if (nknots < 2 ) return; Int_t npoints = graph->GetN(); if (npoints < fMinPoints ) return; // // // 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="<GetN(); fX = new Double_t[fN]; fY0 = new Double_t[fN]; fY1 = new Double_t[fN]; for (Int_t i=0; iGetX()[i]; fY0[i] = fGraph->GetY()[i]; fY1[i] = 0; } }