]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - ITS/AliITSOnlineSDDInjectors.cxx
Correct treatment of tracks with pT<pTmin
[u/mrichter/AliRoot.git] / ITS / AliITSOnlineSDDInjectors.cxx
index e7847367db8e232cdaf1e4f645d15cff7ab81ca1..531bad0bf1e1b1498018f387f217ad933d3ae523 100644 (file)
  * about the suitability of this software for any purpose. It is          *
  * provided "as is" without express or implied warranty.                  *
  **************************************************************************/
+#include <TFile.h>
 #include "AliITSOnlineSDDInjectors.h"
+#include "AliLog.h"
 #include <TH2F.h>
+#include <TF1.h>
 #include <TGraphErrors.h>
 #include <TMath.h>
+#include <TString.h>
+
+/* $Id$ */
 
 ///////////////////////////////////////////////////////////////////
 //                                                               //
 ClassImp(AliITSOnlineSDDInjectors)
 
 const Float_t AliITSOnlineSDDInjectors::fgkSaturation = 1008.;
-const Float_t AliITSOnlineSDDInjectors::fgkJitterTB = 8.;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultLThreshold1 = 8.;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultLThreshold = 15.;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultHThreshold1 =15.;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultHThreshold = 30.;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultMinSpeed = 5.5;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultMaxSpeed = 9.0;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultMaxErr = 1.5;
+const Int_t   AliITSOnlineSDDInjectors::fgkDefaultPolDegree = 3;
+const Float_t AliITSOnlineSDDInjectors::fgkDefaultTimeStep = 50.;
+const UShort_t AliITSOnlineSDDInjectors::fgkDefaultTbMin[kInjLines] = {10,50,100};
+const UShort_t AliITSOnlineSDDInjectors::fgkDefaultTbMax[kInjLines] = {20,70,120};
 
 //______________________________________________________________________
-  AliITSOnlineSDDInjectors::AliITSOnlineSDDInjectors():AliITSOnlineSDD(),fHisto(),fTbZero(0.),fParam(),fPolOrder(0),fMinDriftVel(0.),fMaxDriftVel(0.),fThreshold(0.)
+AliITSOnlineSDDInjectors::AliITSOnlineSDDInjectors():
+  AliITSOnlineSDD(),
+  fHisto(),
+  fTbZero(0.),
+  fRMSTbZero(0.),
+  fNEvents(0),
+  fParam(),
+  fPolDegree(0),
+  fActualPolDegree(0),
+  fMinDriftSpeed(0.),
+  fMaxDriftSpeed(0.),
+  fMaxDriftSpeedErr(0.),
+  fFirstPadForFit(0),
+  fLastPadForFit(0),
+  fPadStatusCutForFit(0),
+  fTimeStep(0.),
+  fUseTimeZeroSignal(kFALSE),
+  fMaxCellsAboveThreshold(40)
 {
   // default constructor
-  SetMinDriftVel();
-  SetMaxDriftVel();
-  SetRangeLine1();
-  SetRangeLine2();
-  SetRangeLine3();
   SetPositions();
-  SetPolOrder();
-  SetThreshold();
+  SetDefaults();
+  SetTimeStep(fgkDefaultTimeStep);
+  for(Int_t i=0;i<kInjPads;i++){ 
+    fSumDriftSpeed[i]=0.;
+    fSumSqDriftSpeed[i]=0.;
+    fSumPadStatus[i]=0;
+    fSumPadStatusCut[i]=0;
+    fNEventsInPad[i]=0;
+  }
+  Reset();
 }
 //______________________________________________________________________
-AliITSOnlineSDDInjectors::AliITSOnlineSDDInjectors(Int_t mod, Int_t sid):AliITSOnlineSDD(mod,sid),fHisto(),fTbZero(0.),fParam(),fPolOrder(0),fMinDriftVel(0.),fMaxDriftVel(0.),fThreshold(0.)
+AliITSOnlineSDDInjectors::AliITSOnlineSDDInjectors(Int_t nddl, Int_t ncarlos, Int_t sid):
+  AliITSOnlineSDD(nddl,ncarlos,sid),
+  fHisto(),
+  fTbZero(0.),
+  fRMSTbZero(0.),
+  fNEvents(0),
+  fParam(),
+  fPolDegree(0),
+  fActualPolDegree(0),
+  fMinDriftSpeed(0.),
+  fMaxDriftSpeed(0.),
+  fMaxDriftSpeedErr(0.),
+  fFirstPadForFit(0),
+  fLastPadForFit(0),
+  fPadStatusCutForFit(0),
+  fTimeStep(0.),
+  fUseTimeZeroSignal(kFALSE),
+  fMaxCellsAboveThreshold(40)
 { 
 // standard constructor
-  SetMinDriftVel();
-  SetMaxDriftVel();
-  SetRangeLine1();
-  SetRangeLine2();
-  SetRangeLine3();
   SetPositions();
-  SetPolOrder();
-  SetThreshold();
+  SetDefaults();
+  SetTimeStep(fgkDefaultTimeStep);
+  for(Int_t i=0;i<kInjPads;i++){ 
+    fSumDriftSpeed[i]=0.;
+    fSumSqDriftSpeed[i]=0.;
+    fSumPadStatus[i]=0;
+    fSumPadStatusCut[i]=0;
+    fNEventsInPad[i]=0;
+  }
+  Reset();
 }
 //______________________________________________________________________
 AliITSOnlineSDDInjectors::~AliITSOnlineSDDInjectors(){
   // Destructor
-  if(fHisto) delete fHisto;  
+  // fHisto should not be deleted here because it points to an histo created 
+  // by the external code which calls the method AnalyzeEvent
+  // if(fHisto) delete fHisto;  
   if(fParam) delete [] fParam;
 }
 //______________________________________________________________________
+void AliITSOnlineSDDInjectors::SetDefaults(){
+  // Sets default values for parameters
+  for(Int_t i=0;i<kInjLines;i++) {
+    SetInjLineRange(i,fgkDefaultTbMin[i],fgkDefaultTbMax[i]);
+    SetUseLine(i,kTRUE);
+    SetThresholds(i,fgkDefaultLThreshold,fgkDefaultHThreshold);
+  }
+  SetThresholds(0,fgkDefaultLThreshold1,fgkDefaultHThreshold1);
+  SetPolDegree(fgkDefaultPolDegree);
+  SetMinDriftSpeed(fgkDefaultMinSpeed);
+  SetMaxDriftSpeed(fgkDefaultMaxSpeed);
+  SetMaxDriftSpeedErr(fgkDefaultMaxErr);
+  SetFitLimits(1,kInjPads-2); // exclude first and last pad
+  SetPadStatusCutForFit();
+}
+//______________________________________________________________________
+void AliITSOnlineSDDInjectors::Set20MHzConfig(){
+  // Sets specific parameters for 20 MHz running
+  SetInjLineRange(0,10,20);
+  SetInjLineRange(1,50,70);
+  SetInjLineRange(2,100,120);
+  SetTimeStep(50.);
+  SetMaxNumberOfCellsPerAnode(40);
+}
+//______________________________________________________________________
+void AliITSOnlineSDDInjectors::Set40MHzConfig(){
+  // Sets specific parameters for 20 MHz running
+  SetInjLineRange(0,20,50);
+  SetInjLineRange(1,90,160);
+  SetInjLineRange(2,170,240);
+  SetTimeStep(25.);
+  SetMaxNumberOfCellsPerAnode(80);
+}
+//______________________________________________________________________
 void AliITSOnlineSDDInjectors::SetPositions(){
-  // 
-  Float_t kLinFromCenterUm[3]={31860.,17460.,660.};
-  Float_t kAnodeFromCenterUm=35085;
-  for(Int_t i=0;i<3;i++){
-    fPosition[i]=kAnodeFromCenterUm-kLinFromCenterUm[i];
+  // Sets drift distances for the 3 injector lines
+  Double_t xLinFromCenterUm[kInjLines]={31860.,17460.,660.};
+  Double_t xAnodeFromCenterUm=35085;
+  for(Int_t i=0;i<kInjLines;i++){
+    fPosition[i]=xAnodeFromCenterUm-xLinFromCenterUm[i];
     fPosition[i]/=10000.; // from microns to cm
   }
 }
 //______________________________________________________________________
 void AliITSOnlineSDDInjectors::Reset(){
-  //
-  for(Int_t i=0;i<kNInjectors;i++){ 
-    fDriftVel[i]=0.;
-    fSigmaDriftVel[i]=0.;
+  // Resets all counters
+  for(Int_t i=0;i<kInjPads;i++){ 
+    fDriftSpeed[i]=0.;
+    fDriftSpeedErr[i]=0.;
   }
-  for(Int_t i=0;i<kNInjectors;i++){
-    for(Int_t j=0;j<3;j++){
+  for(Int_t i=0;i<kInjPads;i++){
+    for(Int_t j=0;j<kInjLines;j++){
       fGoodInj[i][j]=0;
       fCentroid[i][j]=0.;
       fRMSCentroid[i][j]=0.;
@@ -88,48 +180,114 @@ void AliITSOnlineSDDInjectors::Reset(){
 }
 //______________________________________________________________________
 void AliITSOnlineSDDInjectors::AnalyzeEvent(TH2F* his){
-  //
+  // Analyze the current event
+  AddEvent(his);
+  FitDriftSpeedVsAnode();
+}
+//______________________________________________________________________
+void AliITSOnlineSDDInjectors::AddEvent(TH2F* his){
+  // Add the drift speed from current event to the average value
+  if(fNEvents==0){
+    for(Int_t i=0;i<kInjPads;i++){ 
+      fSumDriftSpeed[i]=0.;
+      fSumSqDriftSpeed[i]=0.;
+      fSumPadStatus[i]=0;
+      fSumPadStatusCut[i]=0;
+      fNEventsInPad[i]=0;
+    }
+  }
   Reset();
   fHisto=his;
   FindGoodInjectors();
   FindCentroids();
   CalcTimeBinZero();
-  for(Int_t j=0;j<kNInjectors;j++) CalcDriftVelocity(j);
-  FitDriftVelocityVsAnode();
+  for(Int_t j=0;j<kInjPads;j++){ 
+    CalcDriftSpeed(j);
+    Int_t padStatus=GetInjPadStatus(j);
+    fSumPadStatus[j]+=padStatus;
+    if(padStatus>fPadStatusCutForFit){
+      fSumDriftSpeed[j]+=fDriftSpeed[j];
+      fSumSqDriftSpeed[j]+=fDriftSpeed[j]*fDriftSpeed[j];
+      fSumPadStatusCut[j]+=padStatus;
+      fNEventsInPad[j]++;
+    }
+  }
+  ++fNEvents;
 }
 //______________________________________________________________________
-TGraphErrors* AliITSOnlineSDDInjectors::GetLineGraph(Int_t jlin){
-  // 
-  Float_t x[4],y[4],ex[4],ey[4];
+Double_t AliITSOnlineSDDInjectors::GetRMSDriftSpeed(Int_t ipad) const {
+  // Compute RMS of drift speed distribution on one anode
+  if(fNEventsInPad[ipad]<=1) return 0.;
+  Double_t mean=fSumDriftSpeed[ipad]/(Double_t)fNEventsInPad[ipad];
+  Double_t diff=fSumSqDriftSpeed[ipad]/(Double_t)fNEventsInPad[ipad]-mean*mean;
+  if(diff<0.) diff=0.;
+  return TMath::Sqrt(diff);
+}
+
+//______________________________________________________________________
+void AliITSOnlineSDDInjectors::FitMeanDriftSpeedVsAnode(){
+  // Fits the average drift speed vs.anode number
+  if(fNEvents==0) return;
+  for(Int_t i=0;i<kInjPads;i++){ 
+    fDriftSpeed[i]=GetMeanDriftSpeed(i);
+    Int_t padStatusCut=(Int_t)(GetMeanPadStatusCut(i)+0.5);
+    for(Int_t ilin=0; ilin<kInjLines ; ilin++) fGoodInj[i][ilin]=(padStatusCut&1<<ilin)>>ilin;
+    if(fNEventsInPad[i]>1){
+      Double_t rms=GetRMSDriftSpeed(i);
+      if(rms>0.) fDriftSpeedErr[i]=rms/TMath::Sqrt(fNEventsInPad[i]);
+    }else{
+      for(Int_t ilin=0; ilin<kInjLines ; ilin++) fGoodInj[i][ilin]=0;
+    }
+  }
+  FitDriftSpeedVsAnode();
+  for(Int_t i=0;i<kInjPads;i++){ 
+    Int_t padStatus=(Int_t)(GetMeanPadStatusCut(i)+0.5);
+    for(Int_t ilin=0; ilin<kInjLines ; ilin++) fGoodInj[i][ilin]=(padStatus&1<<ilin)>>ilin;
+  }
+}
+//______________________________________________________________________
+TGraphErrors* AliITSOnlineSDDInjectors::GetTimeVsDistGraph(Int_t jpad) const{
+  // Builds the graph of drift time vs. drift distance
+  const Int_t kPts=kInjLines+1;
+  Float_t x[kPts],y[kPts],ex[kPts],ey[kPts];
   x[0]=0.;
   ex[0]=0.;
   y[0]=fTbZero;
   ey[0]=0.;
-  for(Int_t i=0;i<3;i++){
+  for(Int_t i=0;i<kInjLines;i++){
     x[i+1]=fPosition[i];
     ex[i+1]=0.;
-    y[i+1]=fCentroid[jlin][i];
-    ey[i+1]=fRMSCentroid[jlin][i];
+    y[i+1]=fCentroid[jpad][i];
+    ey[i+1]=fRMSCentroid[jpad][i];
   }
   TGraphErrors *g=new TGraphErrors(4,x,y,ex,ey);
   return g;
 }
+
 //______________________________________________________________________
-Float_t AliITSOnlineSDDInjectors::GetDriftCoordinate(Float_t cAnode, Float_t cTimeBin){
-  //
-  Float_t vel=0;
-  for(Int_t i=0;i<=fPolOrder;i++) vel+=fParam[i]*TMath::Power(cAnode,(Float_t)i);
-  return vel*(cTimeBin-(fTbZero-fgkJitterTB))*25/1000.; 
+TGraphErrors* AliITSOnlineSDDInjectors::GetDriftSpeedGraph() const{
+  // Builds the graph of drift speed vs. anode number
+  Int_t ipt=0;
+  TGraphErrors *g=new TGraphErrors(0);
+  for(Int_t i=0;i<kInjPads;i++){
+    if(fDriftSpeed[i]>0){ 
+      g->SetPoint(ipt,GetAnodeNumber(i),fDriftSpeed[i]);
+      g->SetPointError(ipt,0,fDriftSpeedErr[i]);
+      ipt++;
+    }
+  }
+  return g;
 }
 //______________________________________________________________________
-TGraphErrors* AliITSOnlineSDDInjectors::GetDriftVelocityGraph() const{
-  // 
+TGraphErrors* AliITSOnlineSDDInjectors::GetSelectedDriftSpeedGraph(Int_t minAcceptStatus) const{
+  // TGraphErrors with only pads with status of injector >= minAcceptStatus
   Int_t ipt=0;
   TGraphErrors *g=new TGraphErrors(0);
-  for(Int_t i=0;i<kNInjectors;i++){
-    if(fDriftVel[i]>0){ 
-      g->SetPoint(ipt,GetAnodeNumber(i),fDriftVel[i]);
-      g->SetPointError(ipt,0,fSigmaDriftVel[i]);
+  for(Int_t i=0;i<kInjPads;i++){
+    Int_t padStatus = GetInjPadStatus(i);
+    if(fDriftSpeed[i]>0 && padStatus >= minAcceptStatus ){
+      g->SetPoint(ipt,GetAnodeNumber(i),fDriftSpeed[i]);
+      g->SetPointError(ipt,0,fDriftSpeedErr[i]);
       ipt++;
     }
   }
@@ -137,114 +295,195 @@ TGraphErrors* AliITSOnlineSDDInjectors::GetDriftVelocityGraph() const{
 }
 //______________________________________________________________________
 void AliITSOnlineSDDInjectors::CalcTimeBinZero(){
-  //
-  Float_t tzero=0.,intCont=0.;
+  // Get time zero from trigger signal
+  Double_t tzero=0.,intCont=0.,rmsPeak=0.;
+  Bool_t isTbUsed[256];
+  Int_t nTbUsed=0;
+  for(Int_t i=0;i<256;i++) isTbUsed[i]=0;
   for(Int_t ian=0;ian<fgkNAnodes;ian++){
     for(Int_t itb=1;itb<fTbMin[0];itb++){
-      Float_t cont=fHisto->GetBinContent(itb,ian+1);
-      if(cont>fThreshold){
-       tzero+=cont*float(itb);
-       intCont+=cont;
+      Double_t cont=fHisto->GetBinContent(itb,ian+1);
+      Double_t contm1=fHisto->GetBinContent(itb+1,ian+1);
+      Double_t contp1=fHisto->GetBinContent(itb-1,ian+1);
+      if(cont>fLowThreshold[0]){
+       if(cont>fHighThreshold[0] &&(contm1>fLowThreshold[0] || contp1>fLowThreshold[0])){
+         tzero+=cont*float(itb);
+         rmsPeak+=cont*float(itb)*float(itb);
+         intCont+=cont;
+         if(!isTbUsed[itb]){
+           isTbUsed[itb]=1;
+           ++nTbUsed;
+         }
+       }
       }
     }
   }
-  if(intCont>0) fTbZero=tzero/intCont;
+  if(intCont>0){ 
+    fTbZero=tzero/intCont;
+    fRMSTbZero=TMath::Sqrt(rmsPeak/intCont-fTbZero*fTbZero);
+  }
+  if(nTbUsed==1) fRMSTbZero=0.5; 
 }
+
 //______________________________________________________________________
-void AliITSOnlineSDDInjectors::FitDriftVelocityVsAnode(){
-  const Int_t nn=fPolOrder+1;
-  Float_t **mat = new Float_t*[nn];
-  for(Int_t i=0; i < nn; i++) mat[i] = new Float_t[nn];
-  Float_t *vect = new Float_t[nn];
-  for(Int_t k1=0;k1<nn;k1++){
+void AliITSOnlineSDDInjectors::FitDriftSpeedVsAnode(){
+  // fits the anode dependence of drift speed
+
+  Float_t rangeForMax[2]={78.,178.};
+  PolyFit(fPolDegree);
+  fActualPolDegree=fPolDegree;
+  if(fPolDegree==3){
+    Double_t deltasq=fParam[2]*fParam[2]-3*fParam[1]*fParam[3];
+    Double_t zero1=-999.;
+    Double_t zero2=-999.;
+    if(deltasq>=0. && TMath::Abs(fParam[3])>0.){
+      Double_t delta=TMath::Sqrt(deltasq);
+      zero1=(-fParam[2]+delta)/3./fParam[3];
+      zero2=(-fParam[2]-delta)/3./fParam[3];
+    }
+    Bool_t twoZeroes=kFALSE;
+    Bool_t oneZero=kFALSE;
+    if(zero1>0. && zero1<256. && zero2>0. && zero2<256.) twoZeroes=kTRUE;
+    if(zero1>rangeForMax[0] && zero1<rangeForMax[1]) oneZero=kTRUE;
+    if(zero2>rangeForMax[0] && zero2<rangeForMax[1]) oneZero=kTRUE;
+    if(!oneZero || twoZeroes){
+      PolyFit(2);
+      Double_t xmax=-999.;
+      if(fParam[2]<0.) xmax=-fParam[1]/2./fParam[2];
+      if(xmax>rangeForMax[0] && xmax<rangeForMax[1]){
+       fActualPolDegree=2;
+      }else{
+       Double_t averSpeed=0.;
+       Double_t sumWei=0.;
+       Int_t nUsedPts=0;
+       for(Int_t jpad=fFirstPadForFit; jpad<=fLastPadForFit; jpad++){
+         if(fDriftSpeed[jpad]>0 && GetInjPadStatus(jpad)>fPadStatusCutForFit){
+           Double_t wei=1./fDriftSpeedErr[jpad]/fDriftSpeedErr[jpad];
+           averSpeed+=wei*fDriftSpeed[jpad];
+           sumWei+=wei;
+           nUsedPts++;
+         }
+       }
+       if(sumWei>0.) averSpeed/=sumWei;
+       if(nUsedPts<fPolDegree+1) averSpeed=0;
+       fParam[0]=averSpeed;
+       for(Int_t i=1; i < fPolDegree+1; i++) fParam[i]=0.;
+       fActualPolDegree=0;
+      }
+    }
+  }
+}
+//______________________________________________________________________
+void AliITSOnlineSDDInjectors::PolyFit(Int_t degree){
+  // fits the anode dependence of drift speed with a polynomial function
+  const Int_t kNn=degree+1;
+  const Int_t kDimens=fPolDegree+1;
+
+  Double_t **mat = new Double_t*[kNn];
+  for(Int_t i=0; i < kNn; i++) mat[i] = new Double_t[kNn];
+  Double_t *vect = new Double_t[kNn];
+
+  for(Int_t k1=0;k1<kNn;k1++){
     vect[k1]=0;
-    for(Int_t k2=0;k2<nn;k2++){
+    for(Int_t k2=0;k2<kNn;k2++){
       mat[k1][k2]=0;
-      for(Int_t n=0; n<kNInjectors;n++){
-       Float_t x=(Float_t)GetAnodeNumber(n);
-       if(fDriftVel[n]>0) mat[k1][k2]+=TMath::Power(x,k1+k2)/TMath::Power(fSigmaDriftVel[n],2);
-      }
     }
   }
-  for(Int_t k1=0;k1<nn;k1++){
-    for(Int_t n=0; n<kNInjectors;n++){
-      Float_t x=(Float_t)GetAnodeNumber(n);
-      if(fDriftVel[n]>0) vect[k1]+=fDriftVel[n]*TMath::Power(x,k1)/TMath::Power(fSigmaDriftVel[n],2);
+  Int_t npts = 0;
+  for(Int_t k1=0;k1<kNn;k1++){
+    for(Int_t jpad=fFirstPadForFit; jpad<=fLastPadForFit; jpad++){
+      Double_t x=(Double_t)GetAnodeNumber(jpad);
+      if(fDriftSpeed[jpad]>0 && GetInjPadStatus(jpad)>fPadStatusCutForFit){
+       vect[k1]+=fDriftSpeed[jpad]*TMath::Power(x,k1)/TMath::Power(fDriftSpeedErr[jpad],2);    
+       if(k1==0) npts++;
+       for(Int_t k2=0;k2<kNn;k2++){
+         mat[k1][k2]+=TMath::Power(x,k1+k2)/TMath::Power(fDriftSpeedErr[jpad],2);
+       }
+      }
     }
   }
-  Int_t *iPivot = new Int_t[nn];
-  Int_t *indxR = new Int_t[nn];
-  Int_t *indxC = new Int_t[nn];
-  for(Int_t i=0;i<nn;i++) iPivot[i]=0;
-  Int_t iCol=-1,iRow=-1;
-  for(Int_t i=0;i<nn;i++){
-    Float_t big=0.;
-    for(Int_t j=0;j<nn;j++){
-      if(iPivot[j]!=1){
-       for(Int_t k=0;k<nn;k++){
-          if(iPivot[k]==0){
-            if(TMath::Abs(mat[j][k])>=big){
-              big=TMath::Abs(mat[j][k]);
-              iRow=j;
-              iCol=k;
-            }
+  if(npts<fPolDegree+1){ 
+    if(fParam) delete [] fParam;
+    fParam=new Double_t[kDimens];
+    for(Int_t i=0; i<kDimens;i++)fParam[i]=0;
+  }else{
+    Int_t *iPivot = new Int_t[kNn];
+    Int_t *indxR = new Int_t[kNn];
+    Int_t *indxC = new Int_t[kNn];
+    for(Int_t i=0;i<kNn;i++) iPivot[i]=0;
+    Int_t iCol=-1,iRow=-1;
+    for(Int_t i=0;i<kNn;i++){
+      Double_t big=0.;
+      for(Int_t j=0;j<kNn;j++){
+       if(iPivot[j]!=1){
+         for(Int_t k=0;k<kNn;k++){
+           if(iPivot[k]==0){
+             if(TMath::Abs(mat[j][k])>=big){
+               big=TMath::Abs(mat[j][k]);
+               iRow=j;
+               iCol=k;
+             }
+           }
          }
        }
       }
-    }
-    iPivot[iCol]++;
-    Float_t aux;
-    if(iRow!=iCol){
-      for(Int_t l=0;l<nn;l++){
-       aux=mat[iRow][l];
-       mat[iRow][l]=mat[iCol][l];
-       mat[iCol][l]=aux;
+      iPivot[iCol]++;
+      Double_t aux;
+      if(iRow!=iCol){
+       for(Int_t l=0;l<kNn;l++){
+         aux=mat[iRow][l];
+         mat[iRow][l]=mat[iCol][l];
+         mat[iCol][l]=aux;
+       }
+       aux=vect[iRow];
+       vect[iRow]=vect[iCol];
+       vect[iCol]=aux;
       }
-      aux=vect[iRow];
-      vect[iRow]=vect[iCol];
-      vect[iCol]=aux;
+      indxR[i]=iRow;
+      indxC[i]=iCol;
+      if(mat[iCol][iCol]==0) break;
+      Double_t pivinv=1./mat[iCol][iCol];
+      mat[iCol][iCol]=1;
+      for(Int_t l=0;l<kNn;l++) mat[iCol][l]*=pivinv;
+      vect[iCol]*=pivinv;
+      for(Int_t m=0;m<kNn;m++){
+       if(m!=iCol){
+         aux=mat[m][iCol];
+         mat[m][iCol]=0;
+         for(Int_t n=0;n<kNn;n++) mat[m][n]-=mat[iCol][n]*aux;
+         vect[m]-=vect[iCol]*aux;
+       }
+      }    
     }
-    indxR[i]=iRow;
-    indxC[i]=iCol;
-    if(mat[iCol][iCol]==0) break;
-    Float_t pivinv=1./mat[iCol][iCol];
-    mat[iCol][iCol]=1;
-    for(Int_t l=0;l<nn;l++) mat[iCol][l]*=pivinv;
-    vect[iCol]*=pivinv;
-    for(Int_t m=0;m<nn;m++){
-      if(m!=iCol){
-       aux=mat[m][iCol];
-       mat[m][iCol]=0;
-       for(Int_t n=0;n<nn;n++) mat[m][n]-=mat[iCol][n]*aux;
-       vect[m]-=vect[iCol]*aux;
-      }
-    }    
+    delete [] iPivot;
+    delete [] indxR;
+    delete [] indxC;
+    
+  
+    if(fParam) delete [] fParam;
+    fParam=new Double_t[kDimens];
+    for(Int_t i=0; i<kNn;i++)fParam[i]=vect[i];
+    if(degree<fPolDegree) for(Int_t i=kNn; i<kDimens;i++)fParam[i]=0.;
   }
-  delete [] iPivot;
-  delete [] indxR;
-  delete [] indxC;
-
-  if(fParam) delete [] fParam;
-  fParam=new Float_t[nn];
-  for(Int_t i=0; i<nn;i++)fParam[i]=vect[i];
 
-  for(Int_t i=0; i < nn; i++) delete [] mat[i];
+  for(Int_t i=0; i < kNn; i++) delete [] mat[i];
   delete [] mat;
   delete [] vect;
 }
 //______________________________________________________________________
-void AliITSOnlineSDDInjectors::CalcDriftVelocity(Int_t jlin){
-  // 
-  Float_t sumY=0,sumX=0,sumXX=0,sumYY=0.,sumXY=0,sumWEI=0.;
+void AliITSOnlineSDDInjectors::CalcDriftSpeed(Int_t jpad){
+  // Computes the drift speed from the fit to the 3 injector lines for each anode
+  Double_t sumY=0,sumX=0,sumXX=0,sumYY=0.,sumXY=0,sumWEI=0.;
   Int_t npt=0;
-  Float_t y[3],ey[3];
-  Float_t tzero=0,erry=0;
-  for(Int_t i=0;i<3;i++){ 
-    y[i]=fCentroid[jlin][i];
-    ey[i]=fRMSCentroid[jlin][i];
-  }
-  for(Int_t i=0;i<3;i++){
-    if(fGoodInj[jlin][i]){
+  Double_t y[kInjLines],ey[kInjLines];
+  Double_t tzero=0,erry=0;
+  for(Int_t i=0;i<kInjLines;i++){ 
+    y[i]=fCentroid[jpad][i];
+    ey[i]=fRMSCentroid[jpad][i];
+  }
+  for(Int_t i=0;i<kInjLines;i++){
+    if(!fUseLine[i]) continue;
+    if(fGoodInj[jpad][i] && ey[i]!=0){
       sumY+=y[i]/ey[i]/ey[i];
       sumX+=fPosition[i]/ey[i]/ey[i];
       sumXX+=fPosition[i]*fPosition[i]/ey[i]/ey[i];
@@ -252,144 +491,265 @@ void AliITSOnlineSDDInjectors::CalcDriftVelocity(Int_t jlin){
       sumXY+=fPosition[i]*y[i]/ey[i]/ey[i];
       sumWEI+=1./ey[i]/ey[i];
       tzero=fTbZero/ey[i]/ey[i];
-      erry=ey[i];
+      erry=ey[i]/ey[i]/ey[i];
       npt++;
     }
   }
-  Float_t vel=0,evel=0;
+  Double_t slope=0.,eslope=0.;
+  if(npt==1){
+    slope=(sumY-tzero)/sumX;
+    eslope=erry/sumX;
+  }
   if(npt>1){ 
-    Float_t slope=(sumWEI*sumXY-sumY*sumX)/(sumWEI*sumXX-sumX*sumX);
-    Float_t eslope=TMath::Sqrt(sumWEI/(sumWEI*sumXX-sumX*sumX));
-    vel=1./slope*10000./25.;// micron/ns
-    evel=eslope/slope/slope*10000./25.;// micron/ns
+    if(fUseTimeZeroSignal){
+      sumY+=fTbZero/fRMSTbZero/fRMSTbZero;
+      sumX+=0.;
+      sumXX+=0.;
+      sumYY+=fTbZero*fTbZero/fRMSTbZero/fRMSTbZero;
+      sumXY+=0.;
+      sumWEI+=1./fRMSTbZero/fRMSTbZero;
+    }
+    slope=(sumWEI*sumXY-sumY*sumX)/(sumWEI*sumXX-sumX*sumX);
+    eslope=TMath::Sqrt(sumWEI/(sumWEI*sumXX-sumX*sumX));
   }
-  if(npt==1){
-    Float_t slope=(sumY-tzero)/sumX;
-    Float_t eslope=erry/sumX;
-    vel=1./slope*10000./25.;// micron/ns    
-    evel=eslope/slope/slope*10000./25.;// micron/ns
+
+  Double_t vel=0,evel=0;
+  if(slope!=0. && fTimeStep>0.){
+    vel=1./slope*10000./fTimeStep;// micron/ns
+    evel=eslope/slope/slope*10000./fTimeStep;// micron/ns
   }
-  if(vel>fMaxDriftVel||vel<fMinDriftVel){ 
+  if(vel>fMaxDriftSpeed||vel<fMinDriftSpeed || evel>fMaxDriftSpeedErr){ 
     vel=0.;
     evel=0.;
   }
-  fDriftVel[jlin]=vel;
-  fSigmaDriftVel[jlin]=evel;
+  fDriftSpeed[jpad]=vel;
+  fDriftSpeedErr[jpad]=evel;
 }
 //______________________________________________________________________
-Int_t AliITSOnlineSDDInjectors::GetAnodeNumber(Int_t iInjLine) const{
-  //
+Int_t AliITSOnlineSDDInjectors::GetAnodeNumber(Int_t iInjPad) const{
+  // Injectors location along anodes:
+  // Side left  (UP)   - channel 0: injectors on anodes 0,7,15,...,247,255 
+  // Side right (DOWN) - channel 1: injectors on anodes 0,8,16,...,248,255 
   Int_t ian=-1;
-  if(iInjLine>32) return ian;
-  if(!fSide){
-    ian=iInjLine*8;
-    if(iInjLine==32) ian--;
-  }else{
-    ian=iInjLine*8-1;
-    if(iInjLine==0) ian=0;
+  if(iInjPad>=kInjPads) return ian;
+  if(fSide==1){  // right side
+    ian=iInjPad*8;
+    if(iInjPad==32) ian--;
+  }else{         // left side
+    ian=iInjPad*8-1;
+    if(iInjPad==0) ian=0;
   }
   return ian;
 }
-
+//______________________________________________________________________
+Int_t AliITSOnlineSDDInjectors::GetInjPadNumberFromAnode(Int_t nAnode) const{
+  // Converts anode number into injector pad index
+  Int_t iInjPad=-1;
+  if(fSide==1){  // right side
+    if(nAnode%8==0) iInjPad=nAnode/8;
+    if(nAnode==255) iInjPad=32;
+  }else{         // left side
+    if(nAnode%8==7) iInjPad=1+nAnode/8;
+    if(nAnode==0) iInjPad=0;
+  }
+  if(nAnode>=256) iInjPad=-1;
+  return iInjPad;
+}
+//______________________________________________________________________
+Int_t AliITSOnlineSDDInjectors::GetInjPadStatus(Int_t jpad) const{
+  // returns an integer value with status of injector lines for given pad/anode
+  // status=7  -->  111  all injector are good
+  // status=6  -->  110  1st line (close to anodes) is bad, other two are good
+  // ....
+  // status=1  -->  001  only 1st line (close to anodes) good
+  // status=0  -->  000  all lines are bad
+  Int_t istatus=0;
+  if(jpad>=0 && jpad<kInjPads){
+    for(Int_t jlin=0;jlin<kInjLines;jlin++) istatus+=fGoodInj[jpad][jlin]<<jlin;
+  }
+  return istatus;
+}
 //______________________________________________________________________
 void AliITSOnlineSDDInjectors::FindGoodInjectors(){
-  // 
-  for(Int_t iii=0;iii<kNInjectors;iii++){
-    Int_t ian=GetAnodeNumber(iii);
-    for(Int_t ninj=0;ninj<3;ninj++){
-      for(Int_t jjj=fTbMin[ninj];jjj<fTbMax[ninj];jjj++){
-       Float_t c1=fHisto->GetBinContent(jjj,ian+1);
-       Float_t c2=fHisto->GetBinContent(jjj+1,ian+1);
-       Float_t c3=fHisto->GetBinContent(jjj+2,ian+1);
-       if(c1>fThreshold && c2>fThreshold && c3>fThreshold){ 
-         fGoodInj[iii][ninj]=1;
-         break;
+  // Mark good injector pads
+  // good = 1 cell above high threshold + 1 neighbour above low threshold
+  for(Int_t jpad=0;jpad<kInjPads;jpad++){
+    Int_t ian=GetAnodeNumber(jpad);
+    Int_t countAbove=0;
+    for(Int_t jjj=0; jjj<fHisto->GetNbinsX(); jjj++){
+      Float_t c=fHisto->GetBinContent(jjj+1,ian+1);
+      if(c>0.5) countAbove++;
+    }
+    if(countAbove>fMaxCellsAboveThreshold){
+      for(Int_t jlin=0;jlin<kInjLines;jlin++) fGoodInj[jpad][jlin]=0;           
+    }else{
+      for(Int_t jlin=0;jlin<kInjLines;jlin++){
+       for(Int_t jjj=fTbMin[jlin];jjj<fTbMax[jlin];jjj++){
+         Float_t c1=fHisto->GetBinContent(jjj,ian+1);
+         Float_t c2=fHisto->GetBinContent(jjj+1,ian+1);
+         //    Float_t c3=fHisto->GetBinContent(jjj+2,ian+1);
+         if(c1>fLowThreshold[jlin] && c2>fLowThreshold[jlin]){ 
+           if(c1>fHighThreshold[jlin] || c2>fHighThreshold[jlin]){
+             fGoodInj[jpad][jlin]=1;
+             break;
+           }
+         }
        }
       }
-      //      for(Int_t jjj=fTbMin[ninj];jjj<fTbMax[ninj];jjj++){
-      //       Float_t c1=fHisto->GetBinContent(jjj,ian+1);
-      //       if(c1>=fgkSaturation){
-      //         fGoodInj[iii][ninj]=0;
-      //         break;
-      //       }
-      //      }
     }
   }
 }
 //______________________________________________________________________
 void AliITSOnlineSDDInjectors::FindCentroids(){
-  // 
-  for(Int_t iii=0;iii<kNInjectors;iii++){
-    Int_t ian=GetAnodeNumber(iii);
-    for(Int_t ninj=0;ninj<3;ninj++){
-      if(!fGoodInj[iii][ninj]) continue;
-      Float_t maxcont=0;
+  // Computes the centroids (weighted mean) of teh injector pads
+  for(Int_t jpad=0;jpad<kInjPads;jpad++){
+    Int_t ian=GetAnodeNumber(jpad);
+    for(Int_t jlin=0;jlin<kInjLines;jlin++){
+      if(!fGoodInj[jpad][jlin]) continue;
+      Double_t maxcont=0;
       Int_t ilmax=-1;
-      for(Int_t jjj=fTbMin[ninj];jjj<fTbMax[ninj];jjj++){
-       Float_t cont=fHisto->GetBinContent(jjj,ian+1);
+      for(Int_t jjj=fTbMin[jlin];jjj<fTbMax[jlin];jjj++){
+       Double_t cont=fHisto->GetBinContent(jjj,ian+1);
        if(cont>maxcont){
          maxcont=cont;
          ilmax=jjj;
        }
       }
-      Float_t intCont=0;
+      Double_t intCont=0;
       Int_t jjj=ilmax;
       while(1){
-       Float_t cont=fHisto->GetBinContent(jjj,ian+1);
-       if(cont<fThreshold) break;
+       Double_t cont=fHisto->GetBinContent(jjj,ian+1);
+       if(cont<fLowThreshold[jlin]) break;
        if(cont<fgkSaturation){
-         fCentroid[iii][ninj]+=cont*(Float_t)jjj;
-         fRMSCentroid[iii][ninj]+=cont*TMath::Power((Float_t)jjj,2);
+         fCentroid[jpad][jlin]+=cont*(Double_t)jjj;
+         fRMSCentroid[jpad][jlin]+=cont*(Double_t)jjj*(Double_t)jjj;
          intCont+=cont;
        }
        jjj--;
       }
       jjj=ilmax+1;
       while(1){
-       Float_t cont=fHisto->GetBinContent(jjj,ian+1);
-       if(cont<fThreshold) break;
+       Double_t cont=fHisto->GetBinContent(jjj,ian+1);
+       if(cont<fLowThreshold[jlin]) break;
        if(cont<fgkSaturation){
-         fCentroid[iii][ninj]+=cont*float(jjj);
-         fRMSCentroid[iii][ninj]+=cont*TMath::Power((Float_t)jjj,2);
+         fCentroid[jpad][jlin]+=cont*float(jjj);
+         fRMSCentroid[jpad][jlin]+=cont*(Double_t)jjj*(Double_t)jjj;
          intCont+=cont;
        }
        jjj++;
       }
       if(intCont>0){ 
-       fCentroid[iii][ninj]/=intCont;
-       fRMSCentroid[iii][ninj]=TMath::Sqrt(fRMSCentroid[iii][ninj]/intCont-fCentroid[iii][ninj]*fCentroid[iii][ninj]);
+       fCentroid[jpad][jlin]/=intCont;
+       fRMSCentroid[jpad][jlin]=TMath::Sqrt(fRMSCentroid[jpad][jlin]/intCont-fCentroid[jpad][jlin]*fCentroid[jpad][jlin])/TMath::Sqrt(intCont);
       }
       else{ 
-       fCentroid[iii][ninj]=0.;
-       fRMSCentroid[iii][ninj]=0.;
-       fGoodInj[iii][ninj]=0;
+       fCentroid[jpad][jlin]=0.;
+       fRMSCentroid[jpad][jlin]=0.;
+       fGoodInj[jpad][jlin]=0;
       }
+      if(fRMSCentroid[jpad][jlin]==0) fGoodInj[jpad][jlin]=0;
     }
   }
 }
 //______________________________________________________________________
-void AliITSOnlineSDDInjectors::PrintInjMap(){
-  //
-  for(Int_t iii=0;iii<kNInjectors;iii++){
-    printf("Line%d-Anode%d: %d %d %d\n",iii,GetAnodeNumber(iii),fGoodInj[iii][0],fGoodInj[iii][1],fGoodInj[iii][2]);
+void AliITSOnlineSDDInjectors::PrintInjectorStatus(){
+  // Dumps the status bit of injector pads
+  for(Int_t jpad=0;jpad<kInjPads;jpad++){
+    printf("Line%d-Anode%d: %d %d %d\n",jpad,GetAnodeNumber(jpad),fGoodInj[jpad][0],fGoodInj[jpad][1],fGoodInj[jpad][2]);
   }
 }
 //______________________________________________________________________
 void AliITSOnlineSDDInjectors::PrintCentroids(){
-  //
-  for(Int_t iii=0;iii<kNInjectors;iii++){
-    printf("Line%d-Anode%d: %f+-%f %f+-%f %f+-%f\n",iii,GetAnodeNumber(iii),fCentroid[iii][0],fRMSCentroid[iii][0],fCentroid[iii][1],fRMSCentroid[iii][1],fCentroid[iii][2],fRMSCentroid[iii][2]);
+  // Dumps the drift time centroids of injector pads
+  for(Int_t jpad=0;jpad<kInjPads;jpad++){
+    printf("Line%d-Anode%d: %f+-%f %f+-%f %f+-%f\n",jpad,GetAnodeNumber(jpad),fCentroid[jpad][0],fRMSCentroid[jpad][0],fCentroid[jpad][1],fRMSCentroid[jpad][1],fCentroid[jpad][2],fRMSCentroid[jpad][2]);
   }
 }
 //______________________________________________________________________
-void AliITSOnlineSDDInjectors::WriteToFXS(){
-  //
-  Char_t outfilnam[100];
-  sprintf(outfilnam,"SDDinj_mod%03d_sid%d.data",fModuleId,fSide);
-  FILE* outf=fopen(outfilnam,"w");
-  for(Int_t ic=0;ic<fPolOrder+1;ic++){
+void AliITSOnlineSDDInjectors::WriteToASCII(Int_t evNumb, UInt_t timeStamp, Int_t optAppend){
+  // writes drift speed vs. anode fit parameters into an ASCII file 
+  // to be sent to FXS by the DA and processed by the SHUTTLE
+
+  TString outfilnam;
+  outfilnam.Form("SDDinj_ddl%02dc%02d_sid%d.data",fDDL,fCarlos,fSide);  
+  FILE* outf;
+  if(optAppend==0){ 
+    outf=fopen(outfilnam.Data(),"w");
+    fprintf(outf,"%d\n",fActualPolDegree);
+  }
+  else outf=fopen(outfilnam.Data(),"a");
+  fprintf(outf,"%d   %d   ",evNumb,timeStamp);
+  for(Int_t ic=0;ic<fPolDegree+1;ic++){
     fprintf(outf,"%G ",fParam[ic]);
   }
   fprintf(outf,"\n");
   fclose(outf);  
 }
+//______________________________________________________________________
+TH1F* AliITSOnlineSDDInjectors::GetMeanDriftSpeedVsPadHisto() const{
+  // Builds histogram of average drift speed vs. pad number
+  TString hisnam;
+  hisnam.Form("hdrsp%02dc%02ds%d",fDDL,fCarlos,fSide);
+  TH1F* h=new TH1F(hisnam.Data(),"",kInjPads,-0.5,kInjPads-0.5);
+  if(fNEvents>0){
+    for(Int_t i=0;i<kInjPads;i++){ 
+      h->SetBinContent(i+1,GetMeanDriftSpeed(i));    
+      Double_t rms=GetRMSDriftSpeed(i);
+      Double_t err=0.;
+      if(rms>0.) err=rms/TMath::Sqrt(fNEventsInPad[i]);
+      h->SetBinError(i+1,err);
+    }
+  }
+  return h;
+}
+//______________________________________________________________________
+Bool_t AliITSOnlineSDDInjectors::WriteToROOT(TFile *fil) const {
+  // Writes the output histograms into a root file
+  if(fil==0){ 
+    AliWarning("Invalid pointer to ROOT file");
+    return kFALSE;    
+  }  
+  TString hisnam;
+  fil->cd();
+  hisnam.Form("hdrsp%02dc%02ds%d",fDDL,fCarlos,fSide);
+  TH1F hdsp(hisnam.Data(),"",kInjPads,-0.5,kInjPads-0.5);
+  if(fNEvents==0){
+    AliWarning("Zero analyzed events");
+    return kFALSE;    
+  }  
+    
+  for(Int_t i=0;i<kInjPads;i++){ 
+    hdsp.SetBinContent(i+1,GetMeanDriftSpeed(i));    
+    Double_t rms=GetRMSDriftSpeed(i);
+    Double_t err=0.;
+    if(rms>0.) err=rms/TMath::Sqrt(fNEventsInPad[i]);
+    hdsp.SetBinError(i+1,err);
+  }
+  hdsp.Write();
+  return kTRUE;    
+}
+//______________________________________________________________________
+void AliITSOnlineSDDInjectors::WriteInjectorStatusToASCII(){
+  // dump status of injectors encoded into UInt_t
+  // 5 bits (value 0-31) to store number of pads with given status
+  TString outfilnam;
+  outfilnam.Form("SDDinj_ddl%02dc%02d_sid%d.data",fDDL,fCarlos,fSide);  
+  FILE* outf=fopen(outfilnam.Data(),"a");
+  Int_t n[8]={0,0,0,0,0,0,0,0};
+  for(Int_t jpad=fFirstPadForFit; jpad<=fLastPadForFit; jpad++){
+    Int_t statusPad=GetInjPadStatus(jpad);
+    ++n[statusPad];
+  }
+  UInt_t statusInj=0;
+  statusInj+=(n[7]&0x1F)<<25; // bits 25-29: n. of pads with status 7
+  statusInj+=(n[6]&0x1F)<<20; // bits 20-24: n. of pads with status 6
+  statusInj+=(n[5]&0x1F)<<15; // bits 15-19: n. of pads with status 5
+  statusInj+=(n[4]&0x1F)<<10; // bits 10-14: n. of pads with status 4
+  statusInj+=(n[3]&0x1F)<<5;  // bits  5- 9: n. of pads with status 3
+  statusInj+=(n[2]&0x1F);     // bits  0- 4: n. of pads with status 2
+
+  fprintf(outf,"-99 %u\n",statusInj); // -99 used in preprocessor to find line
+                                      // with injector status info
+  fclose(outf);  
+  
+}