From: acolla Date: Wed, 24 Jan 2007 18:06:26 +0000 (+0000) Subject: new AliSplineFit class. Performs recursive fits to data point arrays X-Git-Url: http://git.uio.no/git/?p=u%2Fmrichter%2FAliRoot.git;a=commitdiff_plain;h=0dd3a2ac0e41f5a75f1f2112e9b3f151cff308a7;hp=b3204f43a1055885102191b8d497802c6847788c;ds=sidebyside new AliSplineFit class. Performs recursive fits to data point arrays (TGraphs), dividing the graph into several parts. Used to reduce data size for entities read from DCS. (Marian, Haavard) --- diff --git a/STEER/AliSplineFit.cxx b/STEER/AliSplineFit.cxx new file mode 100644 index 00000000000..52c096ffacc --- /dev/null +++ b/STEER/AliSplineFit.cxx @@ -0,0 +1,985 @@ +/************************************************************************** + * 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. * + **************************************************************************/ + + +#include "AliSplineFit.h" + +ClassImp(AliSplineFit); + +TLinearFitter AliSplineFit::fitterStatic = TLinearFitter(4,"pol3",""); + +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; iPointAt(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="<