]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - PHOS/AliPHOSRawFitterv2.cxx
Adding histos
[u/mrichter/AliRoot.git] / PHOS / AliPHOSRawFitterv2.cxx
index f38114c07830a4aced8c8f6bf82dd115e701fe9c..46effbfa80dd8c2e729a826d4600e39b75092f91 100644 (file)
 
 /* $Id: $ */
 
-// This class plots samples and qualify their quality according to their shape
+// This class extracts the signal parameters (energy, time, quality)
+// from ALTRO samples. Energy is in ADC counts, time is in time bin units.
+// Class uses FastFitting algorithm to fit sample and extract time and Amplitude 
+// and evaluate sample quality = (chi^2/NDF)/some parameterization providing 
+// efficiency close to 100%
 // 
 // Typical use case:
 //     AliPHOSRawFitter *fitter=new AliPHOSRawFitter();
-//     fitter->SetSamples(sig,sigStart,sigLength);
-//     fitter->SetNBunches(nBunches);
 //     fitter->SetChannelGeo(module,cellX,cellZ,caloFlag);
 //     fitter->SetCalibData(fgCalibData) ;
-//     fitter->Eval();
+//     fitter->Eval(sig,sigStart,sigLength);
 //     Double_t amplitude = fitter.GetEnergy();
 //     Double_t time      = fitter.GetTime();
 //     Bool_t   isLowGain = fitter.GetCaloFlag()==0;
 
-// Author: Dmitri Peressounko (Oct.2008)
-// Modified: Yuri Kharlov (Jul.2009)
+// Author: Dmitri Peressounko (after A.Pavlinov - see RAW/AliCaloFastAltroFitv0.cxx)
 
 // --- ROOT system ---
+#include "TArrayI.h"
 #include "TList.h"
 #include "TMath.h"
-#include "TMinuit.h"
-#include "TCanvas.h"
-#include "TH1.h"
-#include "TH2.h"
+#include "TH1I.h"
 #include "TF1.h"
+#include "TCanvas.h"
+#include "TFile.h"
 #include "TROOT.h"
 
 // --- AliRoot header files ---
@@ -52,16 +53,9 @@ ClassImp(AliPHOSRawFitterv2)
 //-----------------------------------------------------------------------------
 AliPHOSRawFitterv2::AliPHOSRawFitterv2():
   AliPHOSRawFitterv0(),
-  fNtimeSamples(25),
-  fRMScut(11.)
+  fAlpha(0.1),fBeta(0.035),fMax(0) 
 {
   //Default constructor.
-  fLGpar[0]=0.971 ;
-  fLGpar[1]=0.0465;
-  fLGpar[2]=1.56  ;
-  fHGpar[0]=0.941 ; 
-  fHGpar[1]=0.0436;
-  fHGpar[2]=1.65  ;
 }
 
 //-----------------------------------------------------------------------------
@@ -72,35 +66,21 @@ AliPHOSRawFitterv2::~AliPHOSRawFitterv2()
 
 //-----------------------------------------------------------------------------
 AliPHOSRawFitterv2::AliPHOSRawFitterv2(const AliPHOSRawFitterv2 &phosFitter ):
-  AliPHOSRawFitterv0(phosFitter), 
-  fNtimeSamples(25),
-  fRMScut(11.)
+  AliPHOSRawFitterv0(phosFitter),
+  fAlpha(0.1),fBeta(0.035),fMax(0)
 {
   //Copy constructor.
-  fNtimeSamples=phosFitter.fNtimeSamples ;
-  for(Int_t i=0; i<3;i++){
-    fLGpar[i]=phosFitter.fLGpar[i] ;
-    fHGpar[i]=phosFitter.fHGpar[i] ;
-  }
-  fRMScut=phosFitter.fRMScut ;
 }
 
 //-----------------------------------------------------------------------------
-AliPHOSRawFitterv2& AliPHOSRawFitterv2::operator = (const AliPHOSRawFitterv2 &phosFitter)
+AliPHOSRawFitterv2& AliPHOSRawFitterv2::operator = (const AliPHOSRawFitterv2 & /*phosFitter*/)
 {
   //Assignment operator.
-
-  fNtimeSamples=phosFitter.fNtimeSamples ;
-  for(Int_t i=0; i<3;i++){
-    fLGpar[i]=phosFitter.fLGpar[i] ;
-    fHGpar[i]=phosFitter.fHGpar[i] ;
-  }
-  fRMScut=phosFitter.fRMScut ;
   return *this;
 }
 
 //-----------------------------------------------------------------------------
-Bool_t AliPHOSRawFitterv2::Eval()
+Bool_t AliPHOSRawFitterv2::Eval(const UShort_t *signal, Int_t sigStart, Int_t sigLength)
 {
   //Extract an energy deposited in the crystal,
   //crystal' position (module,column,row),
@@ -109,47 +89,42 @@ Bool_t AliPHOSRawFitterv2::Eval()
   //reasonable shape, fits it with Gamma2 function and extracts 
   //energy and time.
 
-  if (fNBunches > 1) {
-    fQuality = 1000;
-    return kTRUE;
-  }
-
+  const Float_t maxEtoFit=5 ; //fit only samples above this energy, accept all samples (with good aRMS) below it
   const Float_t kBaseLine   = 1.0;
   const Int_t   kPreSamples = 10;
 
-  Float_t  pedMean   = 0;
-  Float_t  pedRMS    = 0;
-  Int_t    nPed      = 0;
-  UShort_t maxSample = 0;
-  Int_t    nMax      = 0;
-
-  TCanvas * cs = (TCanvas*)gROOT->FindObjectAny("CSample") ;
-  if(!cs)
-    cs = new TCanvas("CSample","CSample") ;
+  fOverflow = kFALSE ;  
+  fEnergy=0 ;
+  if (fCaloFlag == 2 || fNBunches > 1) {
+    fQuality = 150;
+    return kTRUE;
+  }
+  if(fCaloFlag!=0 && fCaloFlag!=1){//Corrupted sample
+    fQuality=200;
+    fEnergy=0 ;
+    return kTRUE;
+  }
 
-  TH1D * h = (TH1D*)gROOT->FindObjectAny("hSample") ;
-  if(!h) h = new TH1D("hSample","",200,0.,200.) ;
+  //Evaluate pedestals 
+  Float_t pedMean = 0;
+  Float_t pedRMS  = 0;
+  Int_t   nPed    = 0;
+  for (Int_t i=sigLength-kPreSamples; i<sigLength; i++) {
+    nPed++;
+    pedMean += signal[i];
+    pedRMS  += signal[i]*signal[i] ;
+  }
 
+  fEnergy = -111;
+  fQuality= 999. ;
   Double_t pedestal = 0;
-  for (Int_t i=0; i<fLength; i++) {
-    if (i<kPreSamples) {
-      nPed++;
-      pedMean += fSignal[i];
-      pedRMS  += fSignal[i]*fSignal[i] ;
-    }
-    if(fSignal[i] > maxSample) maxSample = fSignal[i];
-    if(fSignal[i] == maxSample) nMax++;
-    h->SetBinContent(i+1,fSignal[i]) ;
-  }
-  fEnergy = (Double_t)maxSample;
-  if (maxSample > 900 && nMax > 2) fOverflow = kTRUE;
 
   if (fPedSubtract) {
     if (nPed > 0) {
       fPedestalRMS=(pedRMS - pedMean*pedMean/nPed)/nPed ;
       if(fPedestalRMS > 0.) 
        fPedestalRMS = TMath::Sqrt(fPedestalRMS) ;
-      fEnergy -= (Double_t)(pedMean/nPed); // pedestal subtraction
+      pedestal = (Double_t)(pedMean/nPed); // pedestal subtraction
     }
     else
       return kFALSE;
@@ -157,95 +132,320 @@ Bool_t AliPHOSRawFitterv2::Eval()
   else {
     //take pedestals from DB
     pedestal = (Double_t) fAmpOffset ;
-    if (fCalibData) {
-      Float_t truePed       = fCalibData->GetADCpedestalEmc(fModule, fCellZ, fCellX) ;
-      Int_t   altroSettings = fCalibData->GetAltroOffsetEmc(fModule, fCellZ, fCellX) ;
-      pedestal += truePed - altroSettings ;
-    }
-    else{
-      AliWarning(Form("Can not read data from OCDB")) ;
-    }
-    fEnergy-=pedestal ;
   }
 
-  if (fEnergy < kBaseLine) {
-    fEnergy = 0;
-    return kTRUE;
-  }
   
-  // calculate time
-  fTime=0. ;
-  Double_t tRMS = 0. ;
-  Double_t tW = 0. ;
-  Int_t cnts=0 ;
-  Double_t a=0,b=0,c=0 ;
-  if(fCaloFlag == 0){ // Low gain
-    a=fLGpar[0] ; 
-    b=fLGpar[1] ; 
-    c=fLGpar[2] ; 
+  //calculate rough quality of the sample and check for overflow
+  Int_t    maxBin=0 ;
+  Int_t    maxAmp=0 ;
+  Int_t    minAmp= signal[0] ;
+  Int_t    nMax = 0 ; //number of points in plato
+  Double_t aMean =0. ;
+  Double_t aRMS  =0. ;
+  Double_t wts   =0 ;
+  Bool_t falling = kTRUE ; //Bad monotoneusly falling sample
+  Bool_t rising = kTRUE ; //Bad monotoneusly riging sample
+  for (Int_t i=0; i<sigLength; i++){
+    if(signal[i] > pedestal){
+      Double_t de = signal[i] - pedestal ;
+      if(de > 1.) {
+       aMean += de*i ;
+       aRMS  += de*i*i ;
+       wts   += de; 
+      }
+      if(signal[i] >  maxAmp){
+        maxAmp = signal[i]; 
+        nMax=0;
+       maxBin = i ;
+      }
+      if(signal[i] == maxAmp){
+        nMax++;
+      }
+      if(signal[i] <  minAmp)
+        minAmp=signal[i] ;
+      if(falling && i>0 && signal[i]<signal[i-1])
+        falling=kFALSE ;
+      if(rising && i>0 && signal[i]>signal[i-1])
+        rising=kFALSE ;
+    }
+  }
+
+  if(rising || falling){//bad "rising" or falling  sample
+    fEnergy =    0. ;
+    fTime   = 0. ; //-999. ;
+    fQuality=  250. ;
+    return kTRUE ;
   }
-  else if(fCaloFlag == 1){ // High gain
-    a=fHGpar[0] ; 
-    b=fHGpar[1] ; 
-    c=fHGpar[2] ; 
+  if(maxAmp-minAmp<3 && maxAmp>7 && sigLength>20){ //bad flat sample
+    fEnergy =    0. ;
+    fTime   = 0; //-999. ;
+    fQuality=  260. ;
+    return kTRUE ;
   }
 
+  fEnergy=Double_t(maxAmp)-pedestal ;
+  if (fEnergy < kBaseLine) fEnergy = 0;
+  fTime = sigStart-sigLength-3;
 
-  fQuality = 0. ;
+  //do not test quality of too soft samples
+  if (wts > 0) {
+    aMean /= wts; 
+    aRMS   = aRMS/wts - aMean*aMean;
+  }
+  if (fEnergy <= maxEtoFit){
+    if (aRMS < 2.) //sigle peak
+      fQuality = 299. ;
+    else
+      fQuality =   0. ;
+    //Evaluate time of signal arriving
+    return kTRUE ;
+  }
+
+  //look for plato on the top of sample
+  if (fEnergy>500 &&  //this is not fluctuation of soft sample
+     nMax>2){ //and there is a plato
+    fOverflow = kTRUE ;
+  }
   
-  for(Int_t i=1; i<fLength && cnts<fNtimeSamples; i++){
-    if(fSignal[i] < pedestal)
-      continue ;
-    Double_t de = fSignal[i]   - pedestal ;
-    Double_t av = fSignal[i-1] - pedestal + de;
-    if(av<=0.) //this is fluctuation around pedestal, skip it
-      continue ;
-    Double_t ds = fSignal[i] - fSignal[i-1] ;
-    Double_t ti = ds/av ;       // calculate log. derivative
-    ti = a/(ti+b)-c*ti ;        // and compare with parameterization
-    ti = i - ti ; 
-    Double_t wi = TMath::Abs(ds) ;
-    fTime += ti*wi ;
-    tW    += wi;
-    tRMS  += ti*ti*wi ;
-    cnts++ ;
-  } 
-
-  if(tW>0.){
-    fTime/=tW ;
-    fQuality = tRMS/tW-fTime*fTime ;
-  }
-  else{
-    fTime=-999. ;
-    fQuality=999. ;
-  }
-
-  Bool_t isBad = 0 ;
-  for(Int_t i=1; i<fLength-1&&!isBad; i++){
-    if(fSignal[i] > fSignal[i-1]+5 && fSignal[i] > fSignal[i+1]+5) { //single jump
-      isBad=1 ;
+
+  //do not fit High Gain samples with overflow
+  if(fCaloFlag==1 && fOverflow){
+    fQuality = 99. ;
+    return kTRUE;
+
+  }
+
+  //----Now fit sample with reasonable shape------
+  TArrayD samples(sigLength); // array of sample amplitudes
+  TArrayD times(sigLength); // array of sample time stamps
+  for (Int_t i=0; i<sigLength; i++) {
+    samples.AddAt(signal[i]-pedestal,sigLength-i-1);
+    times.AddAt(double(i),i);
+  }
+      
+  if(fMax==0)
+    FindMax() ;
+  if(!FindAmpT(samples,times)){
+    if(AliLog::GetDebugLevel("PHOS","AliPHOSRawFitterv2")>3){
+      goto plot ;
+    }
+    else{
+      return kFALSE ;
     }
   }
-  if(pedestal < 10.)
-    isBad=1 ;
-  
-  if(fPedestalRMS > 0.1)
-    isBad=1 ;
+  fEnergy*=fMax ;
+  fTime += sigStart-sigLength-3;
+
+
+  //Impose cut on quality
+//  fQuality/=4. ;
+  fQuality/=1.+0.005*fEnergy ;
+
+  //Draw corrupted samples
+  if(AliLog::GetDebugLevel("PHOS","AliPHOSRawFitterv2")>3){
+    if(fEnergy > 50. ){
+    plot:
+      printf("Sample par: amp=%f,  t0=%f, Quality=%f \n",fEnergy,fTime,fQuality) ;
+      TH1I * h = (TH1I*)gROOT->FindObjectAny("hSamples") ;
+      if(!h) h = new TH1I("hSamples","Samples",65,0.,65.) ;
+      h->Reset() ;
+      for (Int_t i=0; i<sigLength; i++) {
+        h->SetBinContent(i+1,float(samples.At(i))) ;
+      }
+//      TF1 * fffit = new TF1("fffit","[0]+[1]*((x-[2])/[3])^2*exp(2.-2.*(x-[2])/[3])",0.,200.) ;
+      TF1 * fffit = new TF1("fffit","[0]*((x-[1])*(x-[1])*exp(-[2]*(x-[1]))+(x-[1])*exp(-[3]*(x-[1])))",0.,60.) ;
+      fffit->SetParameters(fEnergy/fMax,fTime-(sigStart-sigLength-3),fAlpha,fBeta) ;
+      fffit->SetLineColor(2) ;
+      TCanvas * can = (TCanvas*)gROOT->FindObjectAny("cSamples") ;
+      if(!can){
+        can = new TCanvas("cSamples","cSamples",10,10,600,600) ;
+        can->SetFillColor(0) ;
+        can->SetFillStyle(0) ;
+        can->Range(0,0,1,1);
+        can->SetBorderSize(0);
+      }
+      can->cd() ;
   
-  for(Int_t i=1; i<fLength-1&&!isBad; i++){
-    if(fSignal[i] < pedestal-1)
-      isBad=1 ;
+      TPad * spectrum_1 = new TPad("spectrum_1", "spectrum_1",0.001,0.32,0.99,0.99);
+      spectrum_1->Draw();
+      spectrum_1->cd();
+      spectrum_1->Range(0,0,1,1);
+      spectrum_1->SetFillColor(0);
+      spectrum_1->SetFillStyle(4000);
+      spectrum_1->SetBorderSize(1);
+      spectrum_1->SetBottomMargin(0.012);
+      spectrum_1->SetTopMargin(0.03);
+      spectrum_1->SetLeftMargin(0.10);
+      spectrum_1->SetRightMargin(0.05);
+
+      char title[155] ;
+      snprintf(title,155,"Sample, mod=%d, x=%d, z=%d, Quality=%5.1f",fModule,fCellX,fCellZ,fQuality) ;
+      h->SetTitle(title) ;
+//      h->Fit(fffit,"","",0.,51.) ;
+      h->Draw() ;
+      fffit->Draw("same") ;
+/*
+      sprintf(title,"mod%d_x%d_z%d_HG_qu%4.1f",fModule,fCellX,fCellZ,fQuality) ;
+      TFile fout("samples_bad.root","update") ;
+      h->Write(title);
+      fout.Close() ;
+*/
+      can->cd() ;
+      TPad *spectrum_2 = new TPad("spectrum_2", "spectrum_2",0.001,0.01,0.99,0.32);
+      spectrum_2->SetFillColor(0) ;
+      spectrum_2->SetFillStyle(0) ;
+      spectrum_2->SetGridy() ;
+      spectrum_2->Draw();
+      spectrum_2->Range(0,0,1,1);
+      spectrum_2->SetFillColor(0);
+      spectrum_2->SetBorderSize(1);
+      spectrum_2->SetTopMargin(0.01);
+      spectrum_2->SetBottomMargin(0.25);
+      spectrum_2->SetLeftMargin(0.10);
+      spectrum_2->SetRightMargin(0.05);
+      spectrum_2->cd() ;
+
+      TH1I * hd = (TH1I*)gROOT->FindObjectAny("hSamplesDif") ;
+      if(!hd) hd = new TH1I("hd","Samples",65,0.,65.) ;
+      hd->Reset() ;
+      for (Int_t i=0; i<sigLength; i++) {
+        hd->SetBinContent(i+1,TMath::Max(-1023.,TMath::Min(1023.,samples.At(i)+pedestal-fffit->Eval(i)))) ;
+      }
+      hd->Draw();
+      can->Update() ;
+      printf("Press <enter> to continue\n") ;
+      getchar();
+
+
+      delete fffit ;
+      delete spectrum_1 ;
+      delete spectrum_2 ;
+    }
   }
   
-  if(fEnergy>10. && !isBad ){
-    printf("fE=%f, ped=%f, fQuality=%f, pedRMS=%f \n",fEnergy,pedestal,fQuality,pedRMS) ;
-    if(fOverflow)printf(" Overflow \n") ;
-    if(isBad)printf("bad") ;
-    cs->cd() ;
-    h->Draw() ;
-    cs->Update() ;
-    getchar() ;
-  }
-
   return kTRUE;
 }
+//------------------------------------------------------------------
+Bool_t AliPHOSRawFitterv2::FindAmpT(TArrayD samples, TArrayD times){
+// makes fit
+
+  const Int_t nMaxIter=50 ;   //Maximal number of iterations
+  const Double_t epsdt = 1.e-3 ; //expected precision of t0 calculation
+
+  Double_t dTime=times.At(0)-0.5 ; //Most probable Initial approximation
+//printf(" start fit... \n") ;
+
+  Int_t nPoints = samples.GetSize() ;
+  Double_t dea=TMath::Exp(-fAlpha) ;
+  Double_t deb=TMath::Exp(-fBeta) ;
+  Double_t dt=1.,timeOld=dTime,dfOld=0. ; 
+  for(Int_t iter=0; iter<nMaxIter; iter++){
+    Double_t yy=0.;
+    Double_t yf=0. ;
+    Double_t ydf=0. ;
+    Double_t yddf=0. ;
+    Double_t ff=0. ;
+    Double_t fdf=0. ;
+    Double_t dfdf=0. ;
+    Double_t fddf=0. ;
+    Int_t nfit=0 ;
+    Double_t aexp=TMath::Exp(-fAlpha*(times.At(0)-1.-dTime)) ;
+    Double_t bexp=TMath::Exp(-fBeta*(times.At(0)-1.-dTime)) ;
+    for(Int_t i=0; i<nPoints; i++){
+      Double_t t= times.At(i)-dTime ;
+      aexp*=dea ;
+      bexp*=deb ;
+      if(t<0.) continue ;
+      Double_t y=samples.At(i) ;
+      if(y<=fAmpThreshold)
+        continue ;
+      nfit++ ;
+      Double_t at=fAlpha*t ;
+      Double_t bt = fBeta*t ;
+      Double_t phi=t*(t*aexp+bexp) ;
+      Double_t dphi=t*aexp*(2.-at)+(1.-bt)*bexp ;
+      Double_t ddphi=aexp*(2.-4.*at+at*at)+bexp*fBeta*(bt-2.) ;
+      yy+=y*y ;
+      yf+=y*phi ;
+      ydf+=y*dphi ;
+      yddf+=y*ddphi ;
+      ff+=phi*phi ;
+      fdf+=phi*dphi ;
+      dfdf+=dphi*dphi ;
+      fddf+=phi*ddphi ;
+    }
+
+    if(ff<1.e-09||nfit==0 ){
+      fQuality=199 ;
+      return kFALSE ;
+    }
+    Double_t f=ydf*ff-yf*fdf ;     //d(chi2)/dt
+    Double_t df=yf*(dfdf+fddf)-yddf*ff-ydf*fdf;
+    if(df<=0.){ //we are too far from the root. In the wicinity of root df>0
+      if(iter!=0 && dfOld>0.){//If at previous step df was OK, just reduce step size
+        dt*=0.5 ;
+        dTime=timeOld+dt ;  
+        continue ;
+      }
+      if(f<0){ //f<0 => dTime is too small and we still do not know root region
+        dTime+=2. ;
+        continue ;
+      }
+      else{ //dTime is too large, we are beyond the root region
+        dTime-=2. ;
+        continue ;
+      }
+    }
+    dt=-f/df ; 
+    if(TMath::Abs(dt)<epsdt){
+      fQuality=(yy-yf*yf/ff)/nfit ;
+      fEnergy=yf/ff ;  //ff!=0 already tested
+      fTime=dTime ;
+      return kTRUE ;
+    }
+    //In some cases time steps are huge (derivative ~0)
+    if(dt>10.) dt=10. ;   //restrict step size
+    if(dt<-10.) dt=-5.3 ; //this restriction should be asimmetric to avoid jumping from one point to another
+    timeOld=dTime ;  //remember current position for the case
+    dfOld=df ;       //of reduction of dt step size
+    dTime+=dt ;
+
+    if(dTime>100. || dTime<-30.){ //this is corrupted sample, do not spend time improving accuracy.
+      fQuality=(yy-yf*yf/ff)/nfit ;
+      fEnergy=yf/ff ;  //ff!=0 already tested
+      fTime=dTime ;
+      return kFALSE ;
+    }
+
+  }
+  //failed to find a root, too many iterations
+  fQuality=99.;
+  fEnergy=0 ; 
+  return kFALSE ;
+}
+//_________________________________________
+void AliPHOSRawFitterv2::FindMax(){
+  //Finds maxumum of currecnt parameterization
+  Double_t t=2./fAlpha ;
+  fMax = t*t*TMath::Exp(-fAlpha*t)+t*TMath::Exp(-fBeta*t) ;
+  Double_t dt=15 ;
+  while(dt>0.01){
+     Double_t dfdt=(2.*t-fAlpha*t*t)*TMath::Exp(-fAlpha*t)+(1.-fBeta*t)*TMath::Exp(-fBeta*t) ;
+     if(dfdt>0.)
+        t+=dt ;
+     else
+       t-=dt ;
+     Double_t maxNew = t*t*TMath::Exp(-fAlpha*t)+t*TMath::Exp(-fBeta*t) ;
+     if(maxNew>fMax)
+        fMax=maxNew ;
+     else{
+       dt/=2 ;
+       if(dfdt<0.)
+         t+=dt ;
+       else
+        t-=dt ;
+     }
+  }   
+}