LCOV - code coverage report
Current view: top level - TPC/TPCcalib - AliTPCDcalibRes.cxx (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 2524 0.1 %
Date: 2016-06-14 17:26:59 Functions: 2 81 2.5 %

          Line data    Source code
       1             : #include "AliTPCDcalibRes.h"
       2             : #include "AliCDBPath.h"
       3             : #include "AliCDBEntry.h"
       4             : #include "AliCDBStorage.h"
       5             : #include "AliGRPObject.h"
       6             : #include "AliTriggerRunScalers.h"
       7             : #include "AliTriggerScalersRecord.h"
       8             : #include "AliDAQ.h"
       9             : #include "AliTPCcalibDB.h"
      10             : #include "AliTPCParam.h"
      11             : #include "AliLumiTools.h"
      12             : #include <TKey.h>
      13             : #include <TF2.h>
      14             : 
      15             : using std::swap;
      16             : 
      17             : // this must be standalone f-n, since the signature is important for Chebyshev training
      18             : void trainCorr(int row, float* tzLoc, float* corrLoc);
      19             : 
      20             : // make sure these branches are always connected in InitDeltaFile
      21             : const char* AliTPCDcalibRes::kModeName[kNCollectModes] = {"VDrift calibration","Distortions extraction","Closure test"};
      22             : const char* AliTPCDcalibRes::kExtDetName[kNExtDetComb] = {"TRDonly","TOFonly","ITSonly","TRD|TOF"};
      23             : const char* AliTPCDcalibRes::kControlBr[kCtrNbr] = {"itsOK","trdOK","tofOK","tofBC","nPrimTracks"}; 
      24             : const char* AliTPCDcalibRes::kVoxName[AliTPCDcalibRes::kVoxHDim] = {"z2x","y2x","x","N"};
      25             : const char* AliTPCDcalibRes::kResName[AliTPCDcalibRes::kResDim] = {"dX","dY","dZ","Disp"};
      26             : const float  AliTPCDcalibRes::kMaxResid=20.0f;   
      27             : const float  AliTPCDcalibRes::kMaxResidZVD=40.0f;   
      28             : const float  AliTPCDcalibRes::kMaxTgSlp=2.0;
      29             : 
      30           6 : const float AliTPCDcalibRes::kSecDPhi = 20.f*TMath::DegToRad();
      31             : const float AliTPCDcalibRes::kMaxQ2Pt = 3.0f;
      32             : const float AliTPCDcalibRes::kMinX = 85.0f;
      33             : const float AliTPCDcalibRes::kMaxX = 246.0f;
      34             : const float AliTPCDcalibRes::kMaxZ2X = 1.0f;
      35             : const float AliTPCDcalibRes::kZLim[2] = {2.49725e+02,2.49698e+02};
      36             : const char* AliTPCDcalibRes::kDriftResFileName  = "tmpDriftTree";
      37             : const char* AliTPCDcalibRes::kLocalResFileName  = "tmpDeltaSect";
      38             : const char* AliTPCDcalibRes::kClosureTestFileName  = "closureTestSect";
      39             : const char* AliTPCDcalibRes::kStatOut      = "voxelStat";
      40             : const char* AliTPCDcalibRes::kResOut       = "voxelRes";
      41             : const char* AliTPCDcalibRes::kDriftFileName= "fitDrift";
      42             : const float AliTPCDcalibRes::kDeadZone = 1.5f;
      43             : const float AliTPCDcalibRes::kZeroK = 1e-6;
      44             : const float AliTPCDcalibRes::kInvalidR = 10.f;
      45             : const float AliTPCDcalibRes::kInvalidRes = -900.0f;
      46             : const float AliTPCDcalibRes::kMaxGaussStdDev = 5.0f;
      47             : const ULong64_t AliTPCDcalibRes::kMByte = 1024LL*1024LL;
      48             : 
      49             : const Float_t AliTPCDcalibRes::kTPCRowX[AliTPCDcalibRes::kNPadRows] = { // pad-row center X
      50             :   85.225, 85.975, 86.725, 87.475, 88.225, 88.975, 89.725, 90.475, 91.225, 91.975, 92.725, 93.475, 94.225, 94.975, 95.725,
      51             :   96.475, 97.225, 97.975, 98.725, 99.475,100.225,100.975,101.725,102.475,103.225,103.975,104.725,105.475,106.225,106.975,
      52             :   107.725,108.475,109.225,109.975,110.725,111.475,112.225,112.975,113.725,114.475,115.225,115.975,116.725,117.475,118.225,
      53             :   118.975,119.725,120.475,121.225,121.975,122.725,123.475,124.225,124.975,125.725,126.475,127.225,127.975,128.725,129.475,
      54             :   130.225,130.975,131.725,135.100,136.100,137.100,138.100,139.100,140.100,141.100,142.100,143.100,144.100,145.100,146.100,
      55             :   147.100,148.100,149.100,150.100,151.100,152.100,153.100,154.100,155.100,156.100,157.100,158.100,159.100,160.100,161.100,
      56             :   162.100,163.100,164.100,165.100,166.100,167.100,168.100,169.100,170.100,171.100,172.100,173.100,174.100,175.100,176.100,
      57             :   177.100,178.100,179.100,180.100,181.100,182.100,183.100,184.100,185.100,186.100,187.100,188.100,189.100,190.100,191.100,
      58             :   192.100,193.100,194.100,195.100,196.100,197.100,198.100,199.350,200.850,202.350,203.850,205.350,206.850,208.350,209.850,
      59             :   211.350,212.850,214.350,215.850,217.350,218.850,220.350,221.850,223.350,224.850,226.350,227.850,229.350,230.850,232.350,
      60             :   233.850,235.350,236.850,238.350,239.850,241.350,242.850,244.350,245.850
      61             : };
      62             : const Float_t AliTPCDcalibRes::kTPCRowDX[AliTPCDcalibRes::kNPadRows] = { // pad-row pitch in X
      63             :   0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,
      64             :   0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,
      65             :   0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,0.750,
      66             :   1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,
      67             :   1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,
      68             :   1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,
      69             :   1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,
      70             :   1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500,1.500
      71             : };
      72             : 
      73             : 
      74             : AliTPCDcalibRes* AliTPCDcalibRes::fgUsedInstance = 0;
      75             : 
      76             : 
      77           6 : ClassImp(AliTPCDcalibRes)
      78             : 
      79             : //________________________________________
      80           0 : AliTPCDcalibRes::AliTPCDcalibRes(int run,Long64_t tmin,Long64_t tmax,const char* resList) : 
      81           0 :   fInitDone(kFALSE)
      82           0 :   ,fUseErrInSmoothing(kTRUE)
      83           0 :   ,fSwitchCache(kFALSE)
      84           0 :   ,fFixAlignmentBug(kTRUE)
      85           0 :   ,fApplyZt2Zc(kTRUE)
      86             : 
      87           0 :   ,fChebZSlicePerSide(1)
      88           0 :   ,fChebPhiSlicePerSector(1)
      89           0 :   ,fChebCorr(0)
      90             : 
      91           0 :   ,fRun(run)
      92           0 :   ,fExtDet(kUseTRDonly)
      93           0 :   ,fTMin(tmin)
      94           0 :   ,fTMax(tmax)
      95           0 :   ,fTMinGRP(0)
      96           0 :   ,fTMaxGRP(0)
      97           0 :   ,fTMinCTP(0)
      98           0 :   ,fTMaxCTP(0)
      99           0 :   ,fDeltaTVD(120)
     100           0 :   ,fSigmaTVD(600)
     101           0 :   ,fMaxTracks(4000000)
     102           0 :   ,fNominalTimeBin(2400)
     103           0 :   ,fNominalTimeBinPrec(0.3)
     104           0 :   ,fCacheInp(100)
     105           0 :   ,fLearnSize(1)
     106           0 :   ,fBz(0)
     107           0 :   ,fDeleteSectorTrees(kFALSE) // set to true for production
     108           0 :   ,fResidualList(resList)
     109           0 :   ,fInputChunks(0)
     110           0 :   ,fOCDBPath()
     111             : 
     112           0 :   ,fMinTracksToUse(600000)
     113           0 :   ,fMinTracksPerVDBin(3000)
     114           0 :   ,fMinEntriesVoxel(15)
     115           0 :   ,fNPrimTracksCut(400)
     116           0 :   ,fMinNCl(30)
     117           0 :   ,fMaxDevYHelix(0.3)
     118           0 :   ,fMaxDevZHelix(0.3) // !!! VDrift calib. screas up the Z fit, 0.3 w/o vdrift
     119           0 :   ,fNVoisinMA(3)
     120           0 :   ,fNVoisinMALong(15)
     121           0 :   ,fMaxStdDevMA(25.0)
     122           0 :   ,fMaxRMSLong(0.8)
     123           0 :   ,fMaxRejFrac(0.15)
     124           0 :   ,fTOFBCMin(-25.0)
     125           0 :   ,fTOFBCMax(50.0)
     126           0 :   ,fUseTOFBC(kFALSE)
     127           0 :   ,fFilterOutliers(kTRUE)
     128           0 :   ,fFatalOnMissingDrift(kTRUE)
     129           0 :   ,fMaxFitYErr2(1.0)
     130           0 :   ,fMaxFitXErr2(9.)
     131           0 :   ,fMaxFitXYCorr(0.95)
     132           0 :   ,fLTMCut(0.75)
     133             :   //
     134           0 :   ,fMaxSigY(1.1)
     135           0 :   ,fMaxSigZ(0.7)
     136           0 :   ,fMinValidVoxFracDrift(0.7)
     137           0 :   ,fMaxBadXBinsToCover(4)
     138           0 :   ,fMinGoodXBinsToCover(3)
     139           0 :   ,fMaxBadRowsPerSector(0.4)
     140             :   //
     141           0 :   ,fNY2XBins(15)
     142           0 :   ,fNZ2XBins(5)
     143           0 :   ,fNXBins(-1)
     144           0 :   ,fNXYBinsProd(0)
     145           0 :   ,fDZ2X(0)
     146           0 :   ,fDX(0)
     147           0 :   ,fDZ2XI(0)
     148           0 :   ,fDXI(0)
     149           0 :   ,fNGVoxPerSector(0)
     150             :   //
     151           0 :   ,fMaxY2X(0)
     152           0 :   ,fDY2X(0)
     153           0 :   ,fDY2XI(0)
     154             : 
     155           0 :   ,fKernelType(kGaussianKernel)
     156             : 
     157           0 :   ,fNEvTot(0)
     158           0 :   ,fNTrSelTot(0)
     159           0 :   ,fNTrSelTotWO(0)
     160           0 :   ,fNReadCallTot(0)
     161           0 :   ,fNBytesReadTot(0)
     162           0 :   ,fNTestTracks(0)
     163           0 :   ,fEstTracksPerEvent(0)
     164           0 :   ,fEvRateH(0)
     165           0 :   ,fTracksRate(0)
     166           0 :   ,fTOFBCTestH(0)
     167           0 :   ,fHVDTimeInt(0)
     168           0 :   ,fHVDTimeCorr(0)
     169           0 :   ,fLumiCOG(0)
     170           0 :   ,fLumiCTPGraph(0)
     171           0 :   ,fVDriftParam(0)
     172           0 :   ,fVDriftGraph(0)
     173           0 :   ,fCorrTime(0)
     174             : 
     175           0 :   ,fStatTree(0)
     176             : 
     177           0 :   ,fDTS()
     178           0 :   ,fDTC()
     179           0 :   ,fDTV()
     180           0 :   ,fDeltaStr()
     181             : 
     182           0 :   ,fTimeStamp(0)
     183           0 :   ,fNCl(0)
     184           0 :   ,fQ2Pt(0)
     185           0 :   ,fTgLam(0)
     186           0 : {
     187           0 :   SetTMinMax(tmin,tmax);
     188           0 :   for (int i=0;i<kResDim;i++) {
     189           0 :     for (int j=0;j<2;j++) fNPCheb[i][j] = -1; //determine from job binning// 15;
     190           0 :     fChebPrecD[i] = 100e-4;
     191             :   }
     192             : 
     193           0 :   memset(fLastSmoothingRes,0,kResDim*4*sizeof(double));
     194           0 :   memset(fTestStat,0,kCtrNbr*kCtrNbr*sizeof(float));
     195           0 :   for (int i=kVoxDim;i--;) {
     196           0 :     fUniformBins[i] = kTRUE;
     197           0 :     fKernelScaleEdge[i] = 1.0f;
     198           0 :     fStepKern[i] = 1;
     199           0 :     fKernelWInv[i] = 0; // calculated later
     200           0 :     fSmoothPol2[i] = kFALSE;
     201             :   }
     202           0 :   fSmoothPol2[kVoxX] = kTRUE;
     203           0 :   fSmoothPol2[kVoxF] = kTRUE;
     204             :   //
     205           0 :   for (int i=kVoxHDim;i--;) fNBProdSt[i] = 0;
     206           0 :   for (int i=kVoxDim;i--;) fNBProdSectG[i] = 0;
     207             :   //
     208           0 :   for (int i=0;i<kNSect2;i++) {
     209           0 :     fSectGVoxRes[i] = 0;
     210           0 :     fTmpTree[i] = 0;
     211           0 :     fStatHist[i] = 0;
     212           0 :     fArrNDStat[i] = 0;
     213           0 :     fTmpFile[i] = 0;
     214           0 :     memset(fValidFracXBin[i],0,kNPadRows*sizeof(float));
     215           0 :     fNSmoothingFailedBins[i] = 0;
     216             :   }
     217           0 :   SetKernelType();
     218           0 : }
     219             : 
     220             : //________________________________________
     221             : AliTPCDcalibRes::~AliTPCDcalibRes() 
     222           0 : {
     223             :   // d-tor
     224           0 :   delete fChebCorr;
     225           0 :   delete[] fMaxY2X;
     226           0 :   delete[] fDY2X;
     227           0 :   delete[] fDY2XI;
     228           0 :   delete fVDriftParam;
     229           0 :   delete fVDriftGraph;
     230           0 :   for (int i=0;i<kNSect2;i++) {
     231           0 :     delete fSectGVoxRes[i];
     232           0 :     delete fStatHist[i];
     233             :   }
     234           0 :   delete fTracksRate;
     235           0 :   delete fTOFBCTestH;
     236           0 :   delete fHVDTimeInt;
     237           0 :   delete fHVDTimeCorr;
     238           0 :   delete fInputChunks;
     239           0 : }
     240             : 
     241             : //________________________________________
     242             : void AliTPCDcalibRes::SetExternalDetectors(int det)
     243             : {
     244             :   // set external detectos choice
     245           0 :   if (det<0 || det>=kNExtDetComb) {
     246           0 :     AliErrorF("Invalid external detector %d, allowed range 0:%d, see header file enum{...kNExtDetComb}",det,kNExtDetComb-1);
     247           0 :     return;
     248             :   }
     249           0 :   fExtDet = det;
     250           0 : }
     251             : 
     252             : //________________________________________
     253             : void AliTPCDcalibRes::CalibrateVDrift()
     254             : {
     255             :   // run VDrift calibration from residual trees. 
     256             :   // Parameters  time fDeltaTVD (binning) and  fSigmaTVD (smoothing) can be changed from their
     257             :   // default values by their setters
     258           0 :   TStopwatch sw;
     259             :   const float kSafeMargin = 0.2f;
     260             :   const float kTofEffLow = 0.25f; // if fraction of TOFbc validated to otherwise useful tracks is below this, abandon TOF
     261           0 :   if (!fInitDone) Init();
     262             :   // check available statistics
     263           0 :   if (!EstimateChunkStatistics() || !CollectDataStatistics()) AliFatal("Cannot process further");
     264             :   //
     265           0 :   int nChunks = fInputChunks->GetEntriesFast();
     266           0 :   float ev2Chunk = fNEvTot/nChunks;
     267           0 :   float fracMult = fTestStat[kCtrNtr][kCtrNtr];
     268           0 :   Bool_t useTOFBC = fUseTOFBC;
     269             :   float statEstBCon=0,statEstBCoff=0;
     270             :   // estimate with TOF BC selection
     271           0 :   if      (fExtDet==kUseTRDonly) statEstBCon = fTestStat[kCtrBC0][kCtrTRD];
     272           0 :   else if (fExtDet==kUseTOFonly) statEstBCon = fTestStat[kCtrBC0][kCtrTOF];
     273           0 :   else if (fExtDet==kUseITSonly) statEstBCon = fTestStat[kCtrBC0][kCtrITS];
     274           0 :   else if (fExtDet==kUseTRDorTOF) statEstBCon = fTestStat[kCtrBC0][kCtrTOF]; // contribution of TRD is negligable
     275             :   //
     276           0 :   if      (fExtDet==kUseTRDonly) statEstBCoff = fTestStat[kCtrTRD][kCtrTRD];
     277           0 :   else if (fExtDet==kUseTOFonly) statEstBCoff = fTestStat[kCtrTOF][kCtrTOF];
     278           0 :   else if (fExtDet==kUseITSonly) statEstBCoff = fTestStat[kCtrITS][kCtrITS];
     279           0 :   else if (fExtDet==kUseTRDorTOF) statEstBCoff = fTestStat[kCtrTRD][kCtrTRD]+
     280           0 :                                       fTestStat[kCtrTOF][kCtrTOF]-fTestStat[kCtrTRD][kCtrTOF];
     281             :   //
     282           0 :   Long64_t tmn = fTMin;
     283           0 :   Long64_t tmx = fTMax;
     284           0 :   double duration = tmx - tmn;
     285             :   //
     286           0 :   statEstBCon *= fTestStat[kCtrNtr][kCtrNtr]; // loss due to the mult selection
     287           0 :   statEstBCon *= fNTestTracks*nChunks*(1.-kSafeMargin); // safety margin for losses (outliers etc)
     288             :   //
     289           0 :   statEstBCoff *= fTestStat[kCtrNtr][kCtrNtr]; // loss due to the mult selection
     290           0 :   statEstBCoff *= fNTestTracks*nChunks*(1.-kSafeMargin); // safety margin for losses (outliers etc)
     291             :   //
     292             :   float tofOK=0.f,tofTot=0.f;
     293           0 :   if (fTOFBCTestH && fTOFBCMin<fTOFBCMax) {
     294           0 :     tofOK  = fTOFBCTestH->Integral(fTOFBCTestH->FindBin(fTOFBCMin),fTOFBCTestH->FindBin(fTOFBCMax));
     295           0 :     tofTot = fTOFBCTestH->Integral(1,fTOFBCTestH->GetNbinsX());
     296           0 :     if (tofTot>0) tofOK /= tofTot;
     297             :   }
     298           0 :   AliInfoF("Fraction of TOFBC tracks in %.1f:%.1f window: %.2f (%.2f loss assumed)",
     299             :            fTOFBCMin,fTOFBCMax,tofOK,kSafeMargin);
     300             :   //
     301           0 :   AliInfoF("Estimated tracks stat.for %.1f min: with(w/o) TOF BC selection %d (%d)",
     302             :            duration/60.,int(statEstBCon),int(statEstBCoff));
     303             :   //
     304           0 :   if (statEstBCoff<10) AliFatal("No reasonable data found");
     305             : 
     306           0 :   float tofEff = statEstBCon/statEstBCoff;
     307           0 :   if (tofEff<kTofEffLow) {
     308           0 :     AliWarningF("TOFBC selection eff. %.3f is below the threshold %.3f",tofEff,kTofEffLow);
     309             :     useTOFBC = kFALSE;
     310           0 :   }
     311             :   int ntr2BinBCon=0,ntr2BinBCoff=0,nTimeBins=0;
     312           0 :   float tbinDuration = fNominalTimeBin;
     313             :   // define time bins
     314           0 :   int nWantedTracks = (fMaxTracks+fMinTracksToUse)/2;
     315           0 :   AliInfoF("Nominal requested Ntracks/bin: %d (min:%d max:%d)",nWantedTracks,fMinTracksToUse,fMaxTracks);
     316           0 :   nTimeBins = 1+int(duration/fNominalTimeBin);
     317           0 :   tbinDuration = duration/nTimeBins;
     318           0 :   if (tbinDuration/fNominalTimeBin<(1.-fNominalTimeBinPrec))  {
     319           0 :     nTimeBins = TMath::Max(1,nTimeBins-1);
     320           0 :     tbinDuration = duration/nTimeBins;
     321           0 :   }
     322           0 :   AliInfoF("Suggest %d time bins of %d s durations",nTimeBins,int(tbinDuration));
     323           0 :   ntr2BinBCon  = fNominalTimeBin/duration*statEstBCon;
     324           0 :   ntr2BinBCoff = fNominalTimeBin/duration*statEstBCoff;
     325           0 :   AliInfoF("Estimated Ntracks per time bin: with(w/o) TOF BC: %d(%d)",ntr2BinBCon,ntr2BinBCoff);
     326             :   //  if ( ntr2BinBCon<(nWantedTracks+fMinTracksToUse)/2 ) useTOFBC = kFALSE; // try to keep stat. high
     327           0 :   if ( ntr2BinBCon<nWantedTracks ) useTOFBC = kFALSE; // try to keep stat. high
     328             :   //
     329           0 :   if (!useTOFBC && fUseTOFBC) {
     330           0 :     AliWarning("Switching OFF requested TOF BC validation due to statistics");
     331           0 :     fUseTOFBC = kFALSE;
     332           0 :   }
     333           0 :   fEstTracksPerEvent =  (fUseTOFBC ? statEstBCon:statEstBCoff)/fNEvTot;
     334             :   //
     335           0 :   printf("StatInfo.NTBin\t%d\n",nTimeBins);
     336           0 :   printf("StatInfo.TBinDuration\t%d\n",int(tbinDuration));
     337           0 :   printf("StatInfo.TOFBCsel\t%d\n",fUseTOFBC);
     338             :   // select tracks matching to time window and write compact local trees
     339             :   //
     340           0 :   CollectData(kVDriftCalibMode);
     341             :   //
     342           0 :   FitDrift();
     343           0 :   sw.Stop();
     344           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
     345             :   //
     346           0 : }
     347             : 
     348             : //________________________________________
     349             : void AliTPCDcalibRes::FitDrift()
     350             : {
     351             :   // fit v.drift params
     352             :   const int kUsePoints0 = 1000000; // nominal number of points for 1st estimate
     353             :   const int kUsePoints1 = 10000000; // nominal number of points for time integrated estimate
     354             :   const int kNXBins = 200, kNYBins = 100, kNTCorrBins=100;
     355             :   const int kMinEntriesBin = 100;
     356             :   const float kMaxTCorr = 0.02; // max time correction for vdrift
     357             :   const float kDiscardDriftEdge = 5.; // discard min and max drift values with this margin
     358           0 :   TStopwatch sw;  sw.Start();
     359           0 :   AliSysInfo::AddStamp("FitDrift",0,0,0,0);
     360             :   //
     361           0 :   if (!fInitDone) Init();
     362             :   //
     363           0 :   TString zresFileName = Form("%s.root",kDriftResFileName);
     364           0 :   TFile* zresFile = TFile::Open(zresFileName.Data());
     365           0 :   if (!zresFile) AliFatalF("file %s not found",zresFileName.Data());
     366           0 :   TString treeName = Form("resdrift");
     367           0 :   TTree *zresTree = (TTree*) zresFile->Get(treeName.Data());
     368           0 :   if (!zresTree) AliFatalF("tree %s is not found in file %s",treeName.Data(),zresFileName.Data());
     369             :   //
     370           0 :   dtv_t *dtvP = &fDTV; 
     371           0 :   zresTree->SetBranchAddress("dtv",&dtvP);
     372           0 :   int entries = zresTree->GetEntries();
     373           0 :   if (!entries) AliFatalF("tree %s in %s has no entries",treeName.Data(),zresFileName.Data());
     374             :   //
     375           0 :   float prescale = kUsePoints0/float(entries);
     376           0 :   int npUse = entries*prescale;
     377             :   //
     378           0 :   float *xArr = new Float_t[npUse];
     379           0 :   float *zArr = new Float_t[npUse];
     380             :   int nAcc = 0;
     381           0 :   float dmaxCut = (kZLim[0]+kZLim[1])/2. - kDiscardDriftEdge;
     382           0 :   float res[2],err[3];
     383           0 :   for (int i=0;i<entries;i++) {
     384           0 :     if (gRandom->Rndm()>prescale) continue;
     385           0 :     zresTree->GetEntry(i);
     386           0 :     if (/*fDTV.drift<kDiscardDriftEdge ||*/ fDTV.drift>dmaxCut) continue;
     387           0 :     xArr[nAcc] = fDTV.drift;
     388           0 :     zArr[nAcc] = fDTV.side>0 ? fDTV.dz : -fDTV.dz;
     389           0 :     nAcc++;
     390           0 :   }
     391           0 :   AliInfoF("Will use %d points out of %d for outliers rejection estimate",nAcc,entries);
     392             :   //
     393           0 :   float sigMAD = AliTPCDcalibRes::FitPoly1Robust(nAcc,xArr,zArr,res,err,0.95);
     394           0 :   if (sigMAD<0) AliFatal("Unbinned fit failed");
     395           0 :   AliInfoF("Will clean outliers outside of |dz*side-(%.3e+drift*(%.3e))|<3*%.3f band",res[0],res[1],sigMAD);
     396           0 :   delete[] xArr;
     397           0 :   delete[] zArr;
     398             :   //
     399           0 :   const float outlCut = sigMAD*3.0f;
     400           0 :   delete fHVDTimeInt;
     401           0 :   fHVDTimeInt = new TProfile2D("driftTInt","",kNXBins,-dmaxCut,dmaxCut,kNYBins,-kMaxX,kMaxX);
     402           0 :   fHVDTimeInt->SetXTitle("side*drift");
     403           0 :   fHVDTimeInt->SetYTitle("ylab");  
     404           0 :   fHVDTimeInt->SetZTitle("#deltaz");  
     405           0 :   fHVDTimeInt->SetDirectory(0);
     406           0 :   prescale = kUsePoints1/float(entries);
     407           0 :   npUse = entries*prescale;
     408           0 :   AliInfoF("Will use %d points out of %d for time-integrated estimate",npUse,entries);
     409           0 :   for (int i=0;i<entries;i++) {
     410           0 :     if (gRandom->Rndm()>prescale) continue;
     411           0 :     zresTree->GetEntry(i);
     412           0 :     if (/*fDTV.drift<kDiscardDriftEdge ||*/ fDTV.drift>dmaxCut) continue;
     413           0 :     float dz = fDTV.dz;
     414           0 :     float sdz = fDTV.side>0 ? dz : -dz;
     415           0 :     if (TMath::Abs(sdz - (res[0]+res[1]*fDTV.drift)) > outlCut) continue;
     416           0 :     float sdrift = fDTV.side>0 ? fDTV.drift : -fDTV.drift;
     417             :     //    float d2z = fDTV.drift/kZLim[fDTV.side<0];
     418             :     float wgh = 1;//160./fDTV.r; // use weight as inverse^2 of radius to increase the ITS contribution
     419           0 :     fHVDTimeInt->Fill(sdrift, fDTV.ylab, dz, wgh);
     420             :     //fHVDTimeInt->Fill(sdrift, fDTV.ylab*sdrift/kZLim[fDTV.side<0], sdz); // old way
     421           0 :   }
     422           0 :   float zlim = (kZLim[0]+kZLim[1])/2.f;
     423           0 :   TF2* ftd = new TF2("ftd",Form("[0]*sign(x)+[1]+([2]*y/%.2f+[3])*x",zlim),-250,250,-250,250);
     424             :   //TF2* ftd = new TF2("ftd","[0]+[1]*sign(x)+[2]*sign(x)*y + [3]*sign(x)*x",-250,250,-250,250); // old fun
     425           0 :   ftd->SetParameters(res[0],0.,0.,res[1]); // initial values from unbinned fit
     426           0 :   AliInfoF("Fitting time-integrated vdrift params by %s",ftd->GetTitle());
     427           0 :   TFitResultPtr rf = fHVDTimeInt->Fit(ftd,"0S");
     428           0 :   int ndf = rf->Ndf();
     429           0 :   float chi2 = rf->Chi2();
     430           0 :   AliInfoF("Fit chi2: %f per %d DOFs -> %f",chi2,ndf,ndf>0 ? chi2/ndf : -1.f);
     431           0 :   delete fVDriftParam;
     432           0 :   fVDriftParam = new TVectorD(4);
     433           0 :   for (int i=4;i--;) (*fVDriftParam)[i] = ftd->GetParameter(i);
     434             :   //
     435             :   // time correction
     436           0 :   delete fHVDTimeCorr;
     437           0 :   int ntbins = double(fTMax-fTMin)/fDeltaTVD+1;
     438           0 :   fHVDTimeCorr = new TH2F("driftTCorr","drift time correction",ntbins,fTMin,fTMax+1,kNTCorrBins,-kMaxTCorr,kMaxTCorr);
     439           0 :   fHVDTimeCorr->SetDirectory(0);
     440           0 :   fHVDTimeCorr->SetXTitle("time");
     441           0 :   fHVDTimeCorr->SetYTitle("delta");  
     442             :   //
     443           0 :   double *vpar = fVDriftParam->GetMatrixArray();
     444           0 :   for (int i=0;i<entries;i++) {
     445           0 :     zresTree->GetEntry(i);
     446           0 :     if (/*fDTV.drift<kDiscardDriftEdge ||*/ fDTV.drift>dmaxCut) continue;
     447           0 :     float dz = fDTV.side>0 ? fDTV.dz : -fDTV.dz;
     448           0 :     float sdrift = fDTV.side>0 ? fDTV.drift : -fDTV.drift;
     449           0 :     float d2z = fDTV.drift/kZLim[fDTV.side<0];
     450           0 :     Double_t expected = vpar[0]+vpar[1]*fDTV.side + vpar[2]*fDTV.ylab*d2z + vpar[3]*fDTV.drift;
     451           0 :     dz -= expected;
     452           0 :     if (TMath::Abs(dz) > outlCut) continue;
     453             :     float wgh = 1;//160./fDTV.r; // use weight as inverse^2 of radius to increase the ITS contribution
     454           0 :     fHVDTimeCorr->Fill(fDTV.t,  dz/fDTV.drift, d2z*wgh); // ?? why this weight 
     455           0 :   }
     456             :   //
     457             :   // check results
     458             :   //
     459             :   // extract values
     460           0 :   TF1* gs = new TF1("gs","gaus",-kMaxTCorr,kMaxTCorr);
     461           0 :   TObjArray arrH;
     462           0 :   arrH.SetOwner(kTRUE);
     463           0 :   fHVDTimeCorr->FitSlicesY(gs,0,-1,0,"QNR",&arrH);
     464           0 :   TH1* hEnt = fHVDTimeCorr->ProjectionX("hEnt",1,ntbins);
     465           0 :   TH1* hmean = (TH1*)arrH[1];
     466           0 :   double tArr[ntbins],dArr[ntbins],deArr[ntbins];
     467             :   nAcc = 0;
     468           0 :   for (int i=0;i<ntbins;i++) {
     469           0 :     if (hEnt->GetBinContent(i+1)<kMinEntriesBin) continue;
     470           0 :     deArr[nAcc] = hmean->GetBinError(i+1);
     471           0 :     if (deArr[nAcc]<1e-16) continue;
     472           0 :     tArr[nAcc] = hmean->GetBinCenter(i+1);
     473           0 :     dArr[nAcc] = hmean->GetBinContent(i+1);
     474           0 :     nAcc++;
     475           0 :   }
     476             :   //
     477           0 :   delete fVDriftGraph;
     478           0 :   fVDriftGraph = new TGraphErrors(ntbins);
     479           0 :   double resve[2];
     480             :   int ngAcc = 0;
     481           0 :   for (int i=0;i<ntbins;i++) {
     482           0 :     double tQuery = hEnt->GetBinCenter(i);
     483           0 :     if (!GetSmooth1D(tQuery,resve,nAcc,tArr,dArr,deArr,fSigmaTVD,kGaussianKernel,kFALSE,kTRUE)) {
     484           0 :       AliWarningF("Failed to smooth at point %d out of %d (T=%d)",i,ntbins,int(tQuery));
     485           0 :       continue;
     486             :     }
     487           0 :     fVDriftGraph->SetPoint(ngAcc,tQuery,resve[0]);
     488           0 :     fVDriftGraph->SetPointError(ngAcc,0.5,resve[1]);
     489           0 :     ngAcc++;
     490           0 :   }
     491           0 :   for (int i=ntbins-1;i>=ngAcc; i--) fVDriftGraph->RemovePoint(i); // eliminate empty points
     492             :   //
     493             :   // flag if TOFBC was used for VDrift extraction
     494           0 :   if (fUseTOFBC) fVDriftGraph->SetBit(kVDWithTOFBC);
     495           0 :   else           fVDriftGraph->SetBit(kVDWithoutTOFBC);
     496             :   //
     497           0 :   delete hEnt;
     498           0 :   arrH.Delete();
     499             :   //
     500           0 :   SaveFitDrift();
     501             :   //
     502           0 :   sw.Stop(); 
     503           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
     504           0 :   AliSysInfo::AddStamp("FitDrift",1,0,0,0);
     505           0 : }
     506             : 
     507             : //________________________________________
     508             : void AliTPCDcalibRes::ProcessFromDeltaTrees()
     509             : {
     510             :   // process from residual trees
     511           0 :   TStopwatch sw;
     512             :   // select tracks matching to time window and write compact local trees
     513           0 :   EstimateChunkStatistics();
     514             :   //
     515           0 :   CollectData(kDistExtractMode);
     516             :   //
     517           0 :   if (fNTrSelTot<fMinTracksToUse) {
     518           0 :     AliErrorF("Low statistics: number of contributing tracks %d, min.requested %d",fNTrSelTot,fMinTracksToUse);
     519           0 :     TString stopOnLosStat = gSystem->Getenv("stopOnLowStat");
     520           0 :     if (!stopOnLosStat.IsNull()) {
     521           0 :       AliInfo("Stop on low statistics requested: abandoning map creation");
     522           0 :       exit(1);
     523             :     }
     524             :     else {
     525           0 :       AliInfo("No stop on low statistics requested: starting map creation");
     526             :     }
     527           0 :   }
     528           0 :   ProcessFromLocalBinnedTrees();
     529           0 :   sw.Stop();
     530           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
     531             :   //
     532           0 : }
     533             : 
     534             : //________________________________________
     535             : void AliTPCDcalibRes::ProcessFromLocalBinnedTrees()
     536             : {
     537             :   // process starting from local binned trees created by CollectData(kDistExtractMode)
     538           0 :   TStopwatch sw;
     539           0 :   sw.Start();
     540             : 
     541             :   // do per-sector projections and fits
     542           0 :   ProcessResiduals();
     543             :   //
     544             :   //  ProcessDispersions();
     545             :   //
     546           0 :   CreateCorrectionObject();
     547             :   //
     548           0 :   WriteResTree();
     549             :   //
     550           0 :   sw.Stop();
     551           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
     552           0 : }
     553             : 
     554             : //________________________________________
     555             : void AliTPCDcalibRes::ReProcessFromResVoxTree(const char* resTreeFile, Bool_t backup)
     556             : {
     557             :   // reprocess starting from the raw data filled from existing resVox tree
     558           0 :   TStopwatch sw;
     559           0 :   sw.Start();
     560           0 :   if (!LoadDataFromResTree(resTreeFile)) return;
     561           0 :   ReProcessResiduals();
     562             :   //
     563           0 :   if (fChebCorr) delete fChebCorr; fChebCorr = 0;
     564             :   //
     565           0 :   CreateCorrectionObject();
     566             :   //
     567           0 :   if (backup) { 
     568           0 :     TString inps = resTreeFile;
     569           0 :     if (inps == GetVoxResFileName()) {
     570           0 :       TString inpsb = resTreeFile;
     571           0 :       inpsb.ReplaceAll(".root","_1.root");
     572           0 :       rename(inps.Data(),inpsb.Data());
     573           0 :       AliInfoF("Input file %s backed up to %s",inps.Data(),inpsb.Data());
     574           0 :     }
     575           0 :   }
     576           0 :   WriteResTree();
     577             :   //
     578           0 :   sw.Stop();
     579           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
     580           0 : }
     581             : 
     582             : //________________________________________
     583             : AliTPCDcalibRes* AliTPCDcalibRes::Load(const char* fname)
     584             : {
     585             :   // load AliTPCDcalibRes object from input file
     586           0 :   TString fnames = fname;
     587           0 :   if (!fnames.EndsWith(".root")) {
     588           0 :     if (!fnames.EndsWith("/")) fnames += "/";
     589           0 :     fnames += "alitpcdcalibres.root";
     590             :   }
     591           0 :   TFile* fl = TFile::Open(fnames.Data());
     592           0 :   if (!fl) {AliErrorClassF("Failed to open %s",fnames.Data()); return 0;}
     593           0 :   TList* lstk = fl->GetListOfKeys();
     594           0 :   TIter next(lstk);
     595             :   TKey* key = 0;
     596             :   AliTPCDcalibRes* res = 0;
     597           0 :   while (key=(TKey*)next()) {
     598           0 :     TString keyt = key->GetTitle();
     599           0 :     if (keyt == "AliTPCDcalibRes") {res = (AliTPCDcalibRes*)fl->Get(key->GetName()); break;}
     600           0 :   }
     601           0 :   if (!res) AliErrorClassF("Did not find AliTPCDcalibRes object in %s",fnames.Data());
     602             :   return res;
     603             :   //
     604           0 : }
     605             : 
     606             : //________________________________________
     607             : TTree* AliTPCDcalibRes::LoadTree(const char* fname, int markerStyle,int color)
     608             : {
     609             :   // load voxResTee from input file
     610           0 :   TString fnames = fname;
     611           0 :   if (!fnames.EndsWith(".root")) {
     612           0 :     if (!fnames.EndsWith("/")) fnames += "/";
     613           0 :     fnames += "voxelResTree.root";
     614             :   }
     615           0 :   TFile* fl = TFile::Open(fnames.Data());
     616           0 :   if (!fl) {AliErrorClassF("Failed to open %s",fnames.Data()); return 0;}
     617           0 :   TList* lstk = fl->GetListOfKeys();
     618           0 :   TIter next(lstk);
     619             :   TKey* key = 0;
     620             :   TTree* res = 0;
     621           0 :   while (key=(TKey*)next()) {
     622           0 :     TString keyt = key->GetName();
     623           0 :     if (keyt == "voxRes") {res = (TTree*)fl->Get(key->GetName()); break;}
     624           0 :   }
     625           0 :   if (!res) AliErrorClassF("Did not find voxRes tree in %s",fnames.Data());
     626             :   else {
     627           0 :     res->SetMarkerStyle(markerStyle);
     628           0 :     res->SetMarkerColor(color);
     629           0 :     res->SetLineColor(color);    
     630             :   }
     631             :   return res;
     632             :   //
     633           0 : }
     634             : 
     635             : //________________________________________
     636             : void AliTPCDcalibRes::Save(const char* name)
     637             : {
     638             :   // save itself
     639           0 :   TString names = name;
     640           0 :   if (names.IsNull()) {
     641             :     //    names = Form("%s_run%d_%lld_%lld.root",IsA()->GetName(),fRun,fTMin,fTMax);
     642           0 :     names = Form("%s.root",IsA()->GetName());
     643           0 :     names.ToLower();
     644             :   }
     645           0 :   TFile* flout = TFile::Open(names.Data(),"recreate");
     646           0 :   this->Write("",TObject::kOverwrite);
     647           0 :   flout->Close();
     648           0 :   delete flout;
     649           0 :   AliInfoF("Saved itself to %s",names.Data());
     650             :   //
     651           0 : }
     652             : 
     653             : //________________________________________
     654             : void AliTPCDcalibRes::SaveFitDrift()
     655             : {
     656             :   // save drift parameters in old fitDrift.root format for old way of loading the drift parameters
     657           0 :   TTreeSRedirector *pcstream = new TTreeSRedirector(Form("%s.root",kDriftFileName),"recreate");
     658           0 :   (*pcstream)<<"fitTimeStat"<<
     659           0 :     "grTRDReg.="<<fVDriftGraph<<      // time dependent drift correction TRD - regression estimator
     660           0 :     "paramRobust.="<<fVDriftParam<< // time independent parameters
     661           0 :     "time0="<<fTMin<<             
     662           0 :     "time1="<<fTMax<<
     663           0 :     "run="<<fRun<<
     664             :     "\n";
     665           0 :   delete pcstream;
     666           0 : }
     667             : 
     668             : //==================================================================================
     669             : void AliTPCDcalibRes::Init()
     670             : {          
     671             :   // do the initialization once
     672             :   const int kMaxResBins = 0xff;
     673           0 :   AliSysInfo::AddStamp("ProjStart",0,0,0,0);
     674           0 :   if (fInitDone) {AliInfo("Init already done"); return;}
     675           0 :   if (fRun<1) {
     676           0 :     int run = TString(gSystem->Getenv("runNumber")).Atoi();
     677           0 :     if (run<1) AliFatal("Run number is neither set nor provided via runNumber env.var");
     678           0 :     SetRun(run);
     679           0 :   }
     680             :   //
     681           0 :   AliCDBManager* man = AliCDBManager::Instance();
     682           0 :   if (fOCDBPath.IsNull()) fOCDBPath = "raw://";
     683           0 :   if (!man->IsDefaultStorageSet()) man->SetDefaultStorage(fOCDBPath);
     684           0 :   if (man->GetRun()!=fRun) man->SetRun(fRun); 
     685             :   //
     686             :   // memorize GRP time
     687           0 :   AliGRPObject* grp = (AliGRPObject*)man->Get(AliCDBPath("GRP/GRP/Data"))->GetObject();
     688           0 :   fTMinGRP = grp->GetTimeStart();
     689           0 :   fTMaxGRP = grp->GetTimeEnd();
     690             :   //
     691           0 :   if (fUseTOFBC) { // check if TOF is present
     692           0 :     Int_t activeDetectors = grp->GetDetectorMask();
     693           0 :     if (!(activeDetectors&AliDAQ::DetectorPattern("TOF"))) {
     694           0 :       AliWarning("Disabling TOF BC validation since TOF is not in the GRP");
     695           0 :       fUseTOFBC = kFALSE;
     696           0 :     }
     697           0 :     if (fTOFBCMin>=fTOFBCMax) {
     698           0 :       AliWarningF("Disabling TOF BC validation: inconsistent cuts %.3f:%.3f",fTOFBCMin,fTOFBCMax);
     699           0 :       fUseTOFBC = kFALSE;      
     700           0 :     }
     701           0 :   }
     702             :   // get real data time from CTP scalers
     703           0 :   AliTriggerRunScalers* scalers = (AliTriggerRunScalers*)man->Get(AliCDBPath("GRP/CTP/Scalers"))->GetObject();
     704           0 :   Int_t nEntries = scalers->GetScalersRecords()->GetEntriesFast();
     705           0 :   fTMinCTP = scalers->GetScalersRecord(0         )->GetTimeStamp()->GetSeconds();
     706           0 :   fTMaxCTP = scalers->GetScalersRecord(nEntries-1)->GetTimeStamp()->GetSeconds();
     707             :   //
     708           0 :   if (fTMin<fTMinGRP) fTMin = fTMinGRP;
     709           0 :   if (fTMax>fTMaxGRP) fTMax = fTMaxGRP;
     710             :   //
     711           0 :   AliInfoF("Run time: GRP:%lld:%lld |CTP:%lld:%lld |User:%lld:%lld",fTMinGRP,fTMaxGRP,fTMinCTP,fTMaxCTP,fTMin,fTMax);
     712             :   //
     713           0 :   InitFieldGeom();
     714           0 :   SetName(Form("run%d_%lld_%lld",fRun,fTMin,fTMax));
     715           0 :   SetTitle(IsA()->GetName());
     716             :   //
     717             :   // define boundaries
     718           0 :   InitBinning();
     719             :   //
     720           0 :   LoadVDrift(); //!!!
     721             :   //
     722             :   // prepare aux info for stat and residuals histo bin calculation, see doc of TNDArray bin calculation
     723           0 :   fNBProdSt[kVoxHDim-1] = 1;
     724           0 :   fNBProdSectG[kVoxDim-1] = 1;  
     725           0 :   for (int i=kVoxHDim-1;i--;) {   // +2 to account for under/over-flows
     726           0 :     fNBProdSt[i] = fNBProdSt[i+1]*(2 + ((i==kVoxDim-1) ? kVoxHDim     : fNBins[i+1]));
     727             :   }
     728           0 :   for (int i=kVoxDim-1;i--;) {
     729           0 :     fNBProdSectG[i] = fNBProdSectG[i+1]*fNBins[i+1];
     730             :   }
     731             :   //
     732           0 :   AliSysInfo::AddStamp("Init",0,0,0,0);
     733             :   //
     734           0 :   fInitDone = kTRUE;
     735           0 : }
     736             : 
     737             : //_____________________________________________________
     738             : void AliTPCDcalibRes::CloseTreeFile(TTree* dtree)
     739             : {
     740             :   // close input delta chunk
     741             :   TFile* fl = 0;
     742           0 :   TDirectory* dir = dtree->GetDirectory();
     743           0 :   if (dir) fl = dir->GetFile();
     744           0 :   delete dtree;
     745           0 :   if (fl) fl->Close();
     746           0 :   delete fl;
     747           0 : }
     748             : 
     749             : //_____________________________________________________
     750             : TTree* AliTPCDcalibRes::InitDeltaFile(const char* name, Bool_t connect, const char* treeName) 
     751             : {
     752             :   // init residuals delta file, attach necessary branches
     753             :   // 
     754           0 :   static delta_t *delta = &fDeltaStr;
     755           0 :   TString fileNameString(name);
     756           0 :   if (fileNameString.Contains("alien://") && (!gGrid || (gGrid && !gGrid->IsConnected()))) TGrid::Connect("alien://");
     757           0 :   TFile* file = TFile::Open(fileNameString.Data());
     758           0 :   if (!file) {
     759           0 :     AliErrorF("Cannot open file %s",fileNameString.Data());
     760           0 :     return 0;
     761             :   }
     762           0 :   TTree* tree = (TTree*)file->Get(treeName);
     763           0 :   if (!tree) {
     764           0 :     AliErrorF("No tree %s in %s",treeName,fileNameString.Data());
     765           0 :     delete file; file = 0;
     766           0 :     return 0;
     767             :   }
     768             :   //
     769           0 :   if (!connect) return tree;
     770             :   //
     771           0 :   Bool_t needTRD = fExtDet==kUseTRDorTOF || fExtDet==kUseTRDonly;
     772           0 :   Bool_t needTOF = fExtDet==kUseTRDorTOF || fExtDet==kUseTOFonly;
     773             :   //
     774           0 :   tree->SetCacheLearnEntries(fLearnSize);
     775           0 :   tree->SetCacheSize(0);
     776           0 :   tree->SetCacheSize(fCacheInp*kMByte);
     777             :   //
     778           0 :   tree->SetBranchStatus("*",kFALSE);
     779           0 :   tree->SetBranchStatus("timeStamp",kTRUE);
     780           0 :   tree->SetBranchStatus("itsOK",kTRUE);
     781           0 :   tree->SetBranchStatus("trdOK",kTRUE);
     782           0 :   tree->SetBranchStatus("tofOK",kTRUE);
     783           0 :   tree->SetBranchStatus("vecR.",kTRUE);
     784           0 :   tree->SetBranchStatus("vecSec.",kTRUE);
     785           0 :   tree->SetBranchStatus("vecPhi.",kTRUE);
     786           0 :   tree->SetBranchStatus("vecZ.",kTRUE);
     787           0 :   tree->SetBranchStatus("track.*",kTRUE);      
     788           0 :   tree->SetBranchStatus("npValid",kTRUE);
     789           0 :   tree->SetBranchStatus("its0.",kTRUE);
     790           0 :   tree->SetBranchStatus("its1.",kTRUE);
     791           0 :   tree->SetBranchStatus("tofBC",kTRUE);
     792           0 :   tree->SetBranchStatus("nPrimTracks",kTRUE);
     793             :   //
     794           0 :   tree->SetBranchAddress("timeStamp",&fDeltaStr.timeStamp);
     795           0 :   tree->SetBranchAddress("itsOK",&fDeltaStr.itsOK);
     796           0 :   tree->SetBranchAddress("trdOK",&fDeltaStr.trdOK);
     797           0 :   tree->SetBranchAddress("tofOK",&fDeltaStr.tofOK);
     798           0 :   tree->SetBranchAddress("vecR.",&fDeltaStr.vecR);
     799           0 :   tree->SetBranchAddress("vecSec.",&fDeltaStr.vecSec);
     800           0 :   tree->SetBranchAddress("vecPhi.",&fDeltaStr.vecPhi);
     801           0 :   tree->SetBranchAddress("vecZ.",&fDeltaStr.vecZ);
     802           0 :   tree->SetBranchAddress("track.",&fDeltaStr.param);
     803           0 :   tree->SetBranchAddress("npValid",&fDeltaStr.npValid);
     804           0 :   tree->SetBranchAddress("its0.",&fDeltaStr.vecDYITS);
     805           0 :   tree->SetBranchAddress("its1.",&fDeltaStr.vecDZITS);
     806           0 :   tree->SetBranchAddress("tofBC",&fDeltaStr.tofBC);
     807           0 :   tree->SetBranchAddress("nPrimTracks",&fDeltaStr.nPrimTracks);
     808             :   //
     809           0 :   if (needTRD) {
     810           0 :     tree->SetBranchStatus("trd0.",kTRUE);
     811           0 :     tree->SetBranchStatus("trd1.",kTRUE);
     812           0 :     tree->SetBranchAddress("trd0.",&fDeltaStr.vecDYTRD);
     813           0 :     tree->SetBranchAddress("trd1.",&fDeltaStr.vecDZTRD);
     814             :   }
     815           0 :   if (needTOF) {
     816           0 :     tree->SetBranchStatus("tof0.",kTRUE);
     817           0 :     tree->SetBranchStatus("tof1.",kTRUE);
     818           0 :     tree->SetBranchAddress("tof0.",&fDeltaStr.vecDYTOF);
     819           0 :     tree->SetBranchAddress("tof1.",&fDeltaStr.vecDZTOF);
     820             :   }
     821             :   //
     822           0 :   tree->GetEntry(0);
     823             :   //
     824             :   return tree;
     825           0 : }
     826             : 
     827             : //_____________________________________________________
     828             : Bool_t AliTPCDcalibRes::CollectDataStatistics()
     829             : {
     830             :   // scan even trees to get time coverage
     831           0 :   int nChunks = (!fInputChunks) ? ParseInputList() : fInputChunks->GetEntriesFast();
     832           0 :   AliInfoF("Collecting event rate from %d chunks",nChunks);
     833           0 :   if (!fInitDone) Init();
     834           0 :   int nPrimTrack,timeStamp,tmin=0x7fffffff,tmax=0;
     835           0 :   int nb = int((fTMaxCTP-fTMinCTP)/10.);
     836           0 :   fEvRateH = new TH1F("EvRate","EventRate",1+fTMaxGRP-fTMinGRP,fTMinGRP,fTMaxGRP+1);
     837           0 :   fEvRateH->SetDirectory(0);
     838           0 :   fEvRateH->GetXaxis()->SetTimeFormat();
     839           0 :   fNEvTot = 0;
     840           0 :   for (int ichunk=0;ichunk<nChunks;ichunk++) {
     841           0 :     TTree *tree = InitDeltaFile(fInputChunks->At(ichunk)->GetName(),kFALSE,"eventInfo");
     842           0 :     if (!tree) continue;
     843           0 :     TBranch* brt = tree->GetBranch("timeStamp");
     844           0 :     TBranch* brn = tree->GetBranch("nPrimTrack");
     845           0 :     if (!brt || !brn) {
     846           0 :       AliError("Did not find branch timeStamp or nPromTrack in event info tree");
     847           0 :       CloseTreeFile(tree);
     848           0 :       return kFALSE;
     849             :     }
     850           0 :     brt->SetAddress(&timeStamp);
     851           0 :     brn->SetAddress(&nPrimTrack);
     852           0 :     int nent = tree->GetEntries();
     853           0 :     for (int i=0;i<nent;i++) {
     854           0 :       brt->GetEntry(i);
     855           0 :       brn->GetEntry(i);
     856           0 :       if (fNPrimTracksCut>0 && nPrimTrack>fNPrimTracksCut) continue;
     857           0 :       fEvRateH->Fill(timeStamp);
     858           0 :       if (tmin>timeStamp) tmin = timeStamp;
     859           0 :       if (tmax<timeStamp) tmax = timeStamp;
     860             :     }
     861           0 :     fNEvTot += nent;
     862           0 :     CloseTreeFile(tree);
     863           0 :   }
     864             :   //
     865           0 :   if (fTMin<tmin) fTMin = tmin;
     866           0 :   if (fTMax>tmax) fTMax = tmax;  
     867           0 :   AliInfoF("%d selected events in %d chunks covering %d<T<%d",fNEvTot,nChunks,tmin,tmax);
     868           0 :   printf("StatInfo.minTime\t%lld\n",fTMin);
     869           0 :   printf("StatInfo.maxTime\t%lld\n",fTMax);
     870           0 :   return kTRUE;
     871           0 : }
     872             : 
     873             : //_____________________________________________________
     874             : Int_t AliTPCDcalibRes::ParseInputList()
     875             : {
     876             :   // convert text file to array of file names
     877           0 :   if (fInputChunks) delete fInputChunks;
     878           0 :   if (fResidualList.IsNull()) {
     879           0 :     AliError("Input residuals list is not assigned");
     880           0 :     return 0;
     881             :   }
     882           0 :   TString  chunkList = gSystem->GetFromPipe(TString::Format("cat %s",fResidualList.Data()).Data());
     883           0 :   fInputChunks = chunkList.Tokenize("\n");  
     884           0 :   return fInputChunks->GetEntriesFast();
     885           0 : }
     886             : 
     887             : //_____________________________________________________
     888             : Bool_t AliTPCDcalibRes::EstimateChunkStatistics()
     889             : {
     890             :   // make rough estimate of statistics with different options
     891           0 :   AliInfo("Performing rough statistics check");
     892           0 :   if (!fInitDone) Init();
     893           0 :   if (!AliGeomManager::GetGeometry()) InitFieldGeom(); // in case started from saved object
     894             :   // 
     895             :   // pick 1st chunk
     896           0 :   int nChunks = (!fInputChunks) ? ParseInputList() : fInputChunks->GetEntriesFast();
     897             :   //
     898             :   TTree *tree = 0;
     899             :   int chunk=0; // read 1st accessible chunk
     900           0 :   while ( !(tree=InitDeltaFile(fInputChunks->At(chunk)->GetName())) && ++chunk<nChunks) {}
     901           0 :   if (!tree) {
     902           0 :     AliError("No data chunk was accessible");
     903           0 :     return kFALSE;
     904             :   }
     905             :   //
     906             :   // make sure these branches are always connected in InitDeltaFile
     907             :   const char* kNeedBr[]={"itsOK","trdOK","tofOK","tofBC","nPrimTracks"}; 
     908           0 :   TBranch* br[kCtrNbr];
     909           0 :   for (int i=0;i<kCtrNbr;i++) {
     910           0 :     br[i] = tree->GetBranch(kControlBr[i]);
     911           0 :     if (!br[i]) AliFatalF("Control branch %s is not in the delta tree",kControlBr[i]);
     912           0 :     if (!br[i]->GetAddress()) AliFatalF("Control branch %s address is not set",kControlBr[i]);
     913           0 :     if (!tree->GetBranchStatus(kControlBr[i])) AliFatalF("Control branch %s is not active",kControlBr[i]);
     914             :   }            
     915           0 :   fNTestTracks = tree->GetEntries();
     916           0 :   memset(fTestStat,0,kCtrNbr*kCtrNbr*sizeof(float));
     917           0 :   if (fTOFBCTestH) delete fTOFBCTestH;
     918           0 :   fTOFBCTestH = new TH1F("TOFBCtest",Form("TOF BC for %d tracks",fNTestTracks),1000,-500.,500.);
     919           0 :   fTOFBCTestH->SetDirectory(0);
     920           0 :   Bool_t condOK[kCtrNbr];
     921           0 :   for (int itr=0;itr<fNTestTracks;itr++) {
     922           0 :     for (int ib=kCtrNbr;ib--;) br[ib]->GetEntry(itr);
     923           0 :     condOK[kCtrITS] = fDeltaStr.itsOK;
     924           0 :     condOK[kCtrTRD] = fDeltaStr.trdOK;
     925           0 :     condOK[kCtrTOF] = fDeltaStr.tofOK;
     926           0 :     condOK[kCtrBC0] = fDeltaStr.tofBC>fTOFBCMin && fDeltaStr.tofBC<=fTOFBCMax;
     927           0 :     condOK[kCtrNtr] = fNPrimTracksCut<0 || fDeltaStr.nPrimTracks<=fNPrimTracksCut;
     928           0 :     for (int i=kCtrNbr;i--;) for (int j=kCtrNbr;j--;) if (condOK[i]&&condOK[j]) fTestStat[i][j]++;
     929           0 :     fTOFBCTestH->Fill(fDeltaStr.tofBC);
     930             :   }
     931           0 :   if (fNTestTracks)  for (int i=kCtrNbr;i--;)  for (int j=kCtrNbr;j--;) fTestStat[i][j] /= fNTestTracks;
     932           0 :   AliInfoF("Accepted statistics wrt %d tracks in chunk id=%d (out of %d)",fNTestTracks,chunk,nChunks);
     933           0 :   printf(" %11s",""); for (int i=0;i<kCtrNbr;i++) printf("  %11s",kControlBr[i]); printf("\n");
     934           0 :   for (int i=0;i<kCtrNbr;i++) {
     935           0 :     printf("*%11s",kControlBr[i]);
     936           0 :     for (int j=0;j<kCtrNbr;j++) printf("  %11.5f",fTestStat[i][j]);
     937           0 :     printf("\n");
     938             :   }
     939             :   //
     940           0 :   CloseTreeFile(tree);
     941             :   return kTRUE;
     942           0 : }
     943             : 
     944             : //_____________________________________________________
     945             : void AliTPCDcalibRes::CollectData(const int mode) 
     946             : {
     947             :   const float kEps = 1e-6;
     948             :   const float q2ptIniTolerance = 1.5;
     949           0 :   if (!fInitDone) Init();
     950           0 :   if (!AliGeomManager::GetGeometry()) InitFieldGeom(); // in case started from saved object
     951             :   //
     952           0 :   TStopwatch swTot;
     953           0 :   swTot.Start();
     954           0 :   fNTrSelTot = 0;
     955           0 :   fNTrSelTotWO = 0;
     956           0 :   fNReadCallTot = 0;
     957           0 :   fNBytesReadTot = 0;
     958             :   //
     959           0 :   AliInfo( "***");
     960           0 :   AliInfoF("***   Collecting data in mode: %s",kModeName[mode]);
     961           0 :   AliInfoF("***   Ext.Det.used: %s, TOFBC validation: %s",kExtDetName[fExtDet],fUseTOFBC?"ON":"OFF");
     962           0 :   AliInfo( "***");
     963             :   //
     964           0 :   delete fTracksRate;
     965             :   // init histo for track rate
     966           0 :   fTracksRate = new TH1F("TracksRate","TracksRate", 1+fTMax-fTMin, fTMin,fTMax+1);
     967           0 :   fTracksRate->SetDirectory(0);
     968             :   //
     969           0 :   delete fTracksRate;
     970             :   // init histo for track rate
     971           0 :   fTracksRate = new TH1F("TracksRate","TracksRate", 1+fTMax-fTMin, fTMin,fTMax+1);
     972           0 :   fTracksRate->SetDirectory(0);
     973             :   //
     974             :   float maxAbsResid = kMaxResid - kEps; // discard residuals exceeding this
     975             :   Bool_t correctVDrift = kTRUE;
     976           0 :   if (mode==kVDriftCalibMode) {
     977           0 :     AliInfo("VDrift calibration mode: drift correction disabled");
     978             :     maxAbsResid = kMaxResidZVD - kEps; // vdrift calibration may see larger residuals
     979             :     correctVDrift = kFALSE;
     980           0 :   }
     981             :   else {
     982           0 :     if (!fVDriftGraph || !fVDriftParam) {
     983           0 :       AliErrorF("We are in mode %d but DriftGraph=%p or VDriftParam=%p missing",
     984             :                 mode,fVDriftGraph,fVDriftParam);
     985           0 :       if (fFatalOnMissingDrift) AliFatal("Aborting...");
     986             :     }
     987             :     // make sure TOF usage is consistent with that in VDrift extraction
     988           0 :     Bool_t vdtofUsed1 = fVDriftGraph->TestBit(kVDWithTOFBC);
     989           0 :     Bool_t vdtofUsed0 = fVDriftGraph->TestBit(kVDWithoutTOFBC);
     990           0 :     if (vdtofUsed1 || vdtofUsed0) { // override to what was used in vdrift extraction
     991           0 :       AliInfoF("VDrift has TOFBC flag %s, imposing in distortion map extraction",vdtofUsed1 ? "ON":"OFF");
     992           0 :       if (vdtofUsed1) fUseTOFBC = kTRUE;
     993           0 :       else            fUseTOFBC = kFALSE;
     994             :     }
     995           0 :     else AliInfoF("VDrift has TOFBC flags set, using user provided setting %s",fUseTOFBC ? "ON":"OFF");
     996             :   }
     997           0 :   AliInfoF("TOFBC usage in window %.1f:%.1f is %s",fTOFBCMin,fTOFBCMax,fUseTOFBC ? "ON":"OFF");
     998           0 :   CreateLocalResidualsTrees(mode);
     999             :   //
    1000             :   // if cheb object is present, do on-the-fly init to attach internal structures
    1001           0 :   if (fChebCorr) fChebCorr->Init();
    1002             :   // prepare input tree
    1003           0 :   int nChunks = (!fInputChunks) ? ParseInputList() : fInputChunks->GetEntriesFast();
    1004             :   //
    1005           0 :   AliSysInfo::AddStamp("ProjInit",0,0,0,0);
    1006             :   //
    1007           0 :   for (int ichunk=0;ichunk<nChunks;ichunk++) {
    1008             :     //
    1009             :     int ntrSelChunkWO=0, ntrSelChunk=0,nReadCallsChunk=0,nBytesReadChunk=0;
    1010             :     //
    1011           0 :     TStopwatch swc;
    1012           0 :     swc.Start();
    1013           0 :     TString deltaFName = fInputChunks->At(ichunk)->GetName();
    1014           0 :     TTree *tree = InitDeltaFile(deltaFName.Data());
    1015           0 :     if (!tree) continue;
    1016             :     //
    1017           0 :     TBranch* brTime = tree->GetBranch("timeStamp");
    1018           0 :     TBranch* brTRDOK = tree->GetBranch("trdOK");
    1019           0 :     TBranch* brTOFOK = tree->GetBranch("tofOK");
    1020           0 :     TBranch* brITSOK = tree->GetBranch("itsOK");
    1021             :     TBranch* brTOFBC = 0;
    1022           0 :     if (fUseTOFBC) brTOFBC = tree->GetBranch("tofBC");
    1023             :     //
    1024           0 :     int nTracks = tree->GetEntries();
    1025           0 :     AliInfoF("Processing %d tracks of %s",nTracks,deltaFName.Data());
    1026             : 
    1027           0 :     float residHelixY[kNPadRows],residHelixZ[kNPadRows];
    1028             :     //
    1029             :     // reset the cache when swithching between the timeStamp and Event read modes
    1030             :     Bool_t lastReadMatched = kFALSE; 
    1031           0 :     for (int itr=0;itr<nTracks;itr++) {
    1032           0 :       nBytesReadChunk += brTime->GetEntry(itr);
    1033           0 :       fTimeStamp = fDeltaStr.timeStamp;
    1034           0 :       if (fTimeStamp<fTMin  || fTimeStamp>fTMax) {
    1035           0 :         if (lastReadMatched && fSwitchCache) { // reset the cache
    1036           0 :           tree->SetCacheSize(0);
    1037           0 :           tree->SetCacheSize(fCacheInp*kMByte);
    1038             :           lastReadMatched = kFALSE;
    1039           0 :         }
    1040             :         continue;       
    1041             :       }
    1042           0 :       if (mode==kVDriftCalibMode && EnoughStatForVDrift(fTimeStamp)) continue; // matching but is it needed?
    1043             :       //
    1044           0 :       brITSOK->GetEntry(itr);
    1045           0 :       brTRDOK->GetEntry(itr);
    1046           0 :       brTOFOK->GetEntry(itr);
    1047           0 :       if (!fDeltaStr.itsOK) continue;     
    1048           0 :       if (!fDeltaStr.trdOK && fExtDet==kUseTRDonly) continue;
    1049           0 :       if (!fDeltaStr.tofOK && fExtDet==kUseTOFonly) continue;
    1050           0 :       if (!fDeltaStr.tofOK && !fDeltaStr.trdOK && fExtDet!=kUseITSonly) continue;
    1051             :       //
    1052           0 :       if (brTOFBC && brTOFBC->GetEntry(itr) && (fDeltaStr.tofBC<fTOFBCMin || fDeltaStr.tofBC>fTOFBCMax)) continue;      
    1053             :       //
    1054           0 :       if (!lastReadMatched && fSwitchCache) { // reset the cache before switching to event reading mode
    1055           0 :         tree->SetCacheSize(0);
    1056           0 :         tree->SetCacheSize(fCacheInp*kMByte);
    1057             :       }
    1058             :       lastReadMatched = kTRUE;
    1059           0 :       nBytesReadChunk += tree->GetEntry(itr);
    1060           0 :       if (fNPrimTracksCut>0 && fDeltaStr.nPrimTracks>fNPrimTracksCut) continue;
    1061             :       //
    1062           0 :       fQ2Pt = fDeltaStr.param->GetParameter()[4];
    1063           0 :       fTgLam = fDeltaStr.param->GetParameter()[3];
    1064           0 :       if (TMath::Abs(fQ2Pt)>kMaxQ2Pt*q2ptIniTolerance) continue;
    1065             :       //
    1066           0 :       const Float_t *vSec= fDeltaStr.vecSec->GetMatrixArray();
    1067           0 :       const Float_t *vPhi= fDeltaStr.vecPhi->GetMatrixArray();
    1068           0 :       const Float_t *vR  = fDeltaStr.vecR->GetMatrixArray();
    1069           0 :       const Float_t *vZ  = fDeltaStr.vecZ->GetMatrixArray();
    1070           0 :       const Float_t *vDYITS = fDeltaStr.vecDYITS->GetMatrixArray();
    1071           0 :       const Float_t *vDZITS = fDeltaStr.vecDZITS->GetMatrixArray();
    1072             :       //
    1073             :       const Float_t *vDY=0,*vDZ = 0;
    1074           0 :       if (fExtDet==kUseTRDonly || (fExtDet==kUseTRDorTOF && fDeltaStr.trdOK)) {
    1075           0 :         vDY = fDeltaStr.vecDYTRD->GetMatrixArray();
    1076           0 :         vDZ = fDeltaStr.vecDZTRD->GetMatrixArray();
    1077           0 :       }
    1078           0 :       else if (fExtDet==kUseITSonly) {  // ignore other detectos
    1079           0 :         vDY = fDeltaStr.vecDYITS->GetMatrixArray();
    1080           0 :         vDZ = fDeltaStr.vecDZITS->GetMatrixArray();
    1081           0 :       }
    1082             :       else { // only TOF
    1083           0 :         vDY = fDeltaStr.vecDYTOF->GetMatrixArray();
    1084           0 :         vDZ = fDeltaStr.vecDZTOF->GetMatrixArray();  
    1085             :       }
    1086             :       //
    1087           0 :       fCorrTime = (correctVDrift && fVDriftGraph) ? fVDriftGraph->Eval(fTimeStamp):0; // for VDrift correction
    1088             :       //
    1089           0 :       fNCl = 0;
    1090             :       // 1st iteration: collect data in cluster frame
    1091           0 :       for (int ip=0;ip<fDeltaStr.npValid;ip++) { // 1st fill selected track data to buffer for eventual outlier rejection
    1092           0 :         if (vR[ip]<kInvalidR || vDY[ip]<kInvalidRes || vDYITS[ip]<kInvalidRes) continue;
    1093             :         //
    1094           0 :         fArrX[fNCl]   = -1;
    1095           0 :         fArrR[fNCl]   = vR[ip];  // X (R) is the same for cluster and track
    1096           0 :         fArrZTr[fNCl] = vZ[ip];  // Z of ITS track was stored!!
    1097           0 :         fArrDY[fNCl]  = vDY[ip]; // this is also the track coordinate in cluster frame
    1098           0 :         fArrDZ[fNCl]  = vDZ[ip];
    1099           0 :         fArrPhi[fNCl] = vPhi[ip];
    1100           0 :         int rocID = TMath::Nint(vSec[ip]);
    1101             :         //
    1102             :         // !!! fArrZTr corresponds to ITS track Z, we need that of TRD-ITS
    1103           0 :         fArrZTr[fNCl] += fArrDZ[fNCl] - vDZITS[ip]; // recover ITS-TRD track position from ITS and deltas
    1104             :         
    1105           0 :         if (fFixAlignmentBug && !fDeltaStr.param->TestBit(kAlignmentBugFixedBit)) {
    1106           0 :           FixAlignmentBug(rocID, fQ2Pt, fBz, fArrPhi[fNCl], fArrR[fNCl], fArrZTr[fNCl], fArrDY[fNCl],fArrDZ[fNCl]);
    1107             :         }
    1108           0 :         if (fArrPhi[fNCl]<0) fArrPhi[fNCl] += 2.*TMath::Pi();
    1109             :         //
    1110             :         // correct for drift velocity calibration if needed
    1111           0 :         if (correctVDrift) fArrDZ[fNCl] += GetDriftCorrection(fArrZTr[fNCl],fArrR[fNCl],fArrPhi[fNCl],rocID);
    1112             :         //
    1113           0 :         fArrSectID[fNCl] = rocID%kNSect2; // 0-36 for sectors from A0 to C17
    1114             :         //
    1115           0 :         fNCl++;
    1116           0 :       }
    1117             :       // fit track coordinates by helix to get interpolated track q/pt: 
    1118             :       // more precise than the distorted TPC q/pt
    1119           0 :       if (fNCl<fMinNCl) continue;
    1120             :       //
    1121           0 :       ntrSelChunkWO++;
    1122             :       //
    1123             :       float q2ptTPC = fQ2Pt;
    1124           0 :       Bool_t resH = CompareToHelix(residHelixY,residHelixZ);
    1125             :       //
    1126           0 :       if (fFilterOutliers && !resH) continue; // too strong deviation to helix, discard track
    1127           0 :       if (TMath::Abs(fQ2Pt)>kMaxQ2Pt) continue; // now we have more precise estimate of q/pt
    1128             :       //
    1129             :       // 2nd iteration: convert everything to sector frame
    1130             :       // *****************************************************************
    1131             :       //
    1132             :       // All these manipulations are needed because the ResidualTree is stored
    1133             :       // in cluster frame, while we need the sector frame
    1134             :       //
    1135             :       // *****************************************************************
    1136           0 :       int nc0 = fNCl; 
    1137           0 :       fNCl = 0;
    1138           0 :       for (int ip=0;ip<nc0;ip++) {
    1139           0 :         int side = ((fArrSectID[ip] /kNSect)&0x1);
    1140           0 :         float sna = TMath::Sin(fArrPhi[ip]-(0.5f +fArrSectID[ip]%kNSect)*kSecDPhi);
    1141           0 :         float csa = TMath::Sqrt((1.f-sna)*(1.f+sna));
    1142             :         //
    1143             :         // by using propagation in cluster frame in AliTPCcalibAlignInterpolation::Process,
    1144             :         // the X of the track is evaluated not at the pad-row x=r*csa but at x=r*sca-dy*sna
    1145           0 :         double xrow = fArrR[ip]*csa;
    1146           0 :         double dx   = fArrDY[ip]*sna;
    1147             :         double xtr  = xrow - dx;
    1148           0 :         double ycl  = fArrR[ip]*sna;      // cluster Y in the sector frame
    1149           0 :         double ytr  = ycl + fArrDY[ip]*csa; // track Y in the sector frame at x=xtr is 
    1150             :         //
    1151           0 :         double ztr  = fArrZTr[ip];          // Z of the track at x=xtr
    1152           0 :         double zcl  = ztr - fArrDZ[ip];     // and the Z of the cluster is Ztr-deltaZ
    1153             :         //
    1154             :         // Now we need to take the track to real pad-row X
    1155             :         // use linear extrapolation:
    1156           0 :         float tgs = fArrTgSlp[ip];
    1157           0 :         if (TMath::Abs(tgs)>kMaxTgSlp) continue;
    1158           0 :         ytr += dx*tgs;
    1159           0 :         double csXtrInv = TMath::Sqrt(1.+tgs*tgs); // (inverse cosine of track angle)
    1160           0 :         ztr += dx*fTgLam*csXtrInv;
    1161             :         //
    1162             :         // assign to arrays and recalculate residuals
    1163           0 :         fArrX[fNCl]   = xrow;
    1164           0 :         fArrYTr[fNCl] = ytr;
    1165           0 :         fArrZTr[fNCl] = ztr;
    1166             :         //
    1167           0 :         fArrYCl[fNCl] = ycl;
    1168           0 :         fArrZCl[fNCl] = zcl;
    1169           0 :         fArrDY[fNCl]  = ytr - ycl;
    1170           0 :         fArrDZ[fNCl]  = ztr - zcl;
    1171             :         //
    1172             :         // we don't want under/overflows
    1173           0 :         if (TMath::Abs(fArrDY[fNCl])>maxAbsResid) continue;
    1174           0 :         if (TMath::Abs(fArrDZ[fNCl])>maxAbsResid) continue;
    1175             :         //
    1176           0 :         if (fArrX[fNCl]<kMinX || fArrX[fNCl]>kMaxX) continue;
    1177           0 :         if (TMath::Abs(fArrZCl[fNCl])>kZLim[side]) continue;;
    1178             :         //
    1179             :         // End of manipulations to go to the sector frame
    1180             :         //
    1181           0 :         fNCl++;
    1182           0 :       }
    1183             : 
    1184           0 :       if (fFilterOutliers && !ValidateTrack()) continue;
    1185             : 
    1186           0 :       ntrSelChunk++;
    1187             :       
    1188           0 :       switch(mode) {
    1189           0 :       case kVDriftCalibMode:     FillDriftResidualsTrees(); break;
    1190           0 :       case kDistExtractMode:     FillLocalResidualsTrees(); break;
    1191           0 :       case kDistClosureTestMode: FillCorrectedResiduals();  break;
    1192           0 :       default: AliFatalF("Uknown mode %d",mode);
    1193           0 :       };
    1194           0 :     } // loop over tracks
    1195             :     //
    1196           0 :     swc.Stop();
    1197           0 :     TFile* chunkFile = tree->GetDirectory()?tree->GetDirectory()->GetFile():0;
    1198           0 :     nReadCallsChunk =  chunkFile ? chunkFile->GetReadCalls():0;
    1199           0 :     AliInfoF("Chunk%3d: selected %d tracks (%d with outliers) from chunk %d | %.1f MB read in %d read calls",
    1200           0 :              ichunk,ntrSelChunk,ntrSelChunkWO, ichunk,float(nBytesReadChunk)/kMByte,nReadCallsChunk); swc.Print();
    1201           0 :     fNTrSelTot += ntrSelChunk;
    1202           0 :     fNTrSelTotWO += ntrSelChunkWO;
    1203           0 :     fNReadCallTot += nReadCallsChunk;
    1204           0 :     fNBytesReadTot += nBytesReadChunk;
    1205             :     //
    1206           0 :     CloseTreeFile(tree);
    1207           0 :     AliSysInfo::AddStamp("ProjTreeLoc", ichunk ,fNTrSelTot,fNTrSelTot,fNReadCallTot );
    1208             :     //
    1209           0 :     if (fNTrSelTot > fMaxTracks) {
    1210           0 :       AliInfo("Max number of tracks exceeded");
    1211           0 :       break;
    1212             :     }
    1213           0 :     if (mode==kVDriftCalibMode && EnoughStatForVDrift()) {
    1214           0 :       AliInfo("Sifficient statistics for VDrift calibration collected");
    1215           0 :       break;
    1216             :     }
    1217             :     //
    1218           0 :   } // loop over chunks
    1219             :   //
    1220             :   // write/close local trees
    1221           0 :   CloseLocalResidualsTrees(mode);
    1222             :   //
    1223           0 :   AliInfoF("Summary: selected %d tracks (%d with outliers) | %.1f MB read in %d read calls",
    1224             :            fNTrSelTot,fNTrSelTotWO,float(fNBytesReadTot)/kMByte,fNReadCallTot); 
    1225           0 :   swTot.Print();
    1226             : 
    1227           0 :   AliSysInfo::AddStamp("ProjTreeLocSave");
    1228             : 
    1229           0 :   if (mode==kDistExtractMode) WriteStatHistos();
    1230             :   //
    1231           0 : }
    1232             : 
    1233             : //________________________________________________
    1234             : Bool_t AliTPCDcalibRes::EnoughStatForVDrift(int tstamp, float maxHolesFrac) 
    1235             : {
    1236             :   // check if collected stat. is enough for VDrift calibration
    1237             :   // when called with positive timestamp, check just the occupancy of the bin it belong to
    1238             :   static Bool_t *binStat = 0;
    1239             :   static int    nBinStat = 0;
    1240           0 :   if (!binStat) {
    1241           0 :     nBinStat = (fTMax-fTMin)/fDeltaTVD+1;
    1242           0 :     binStat = new Bool_t[nBinStat];
    1243           0 :     memset(binStat,0,nBinStat*sizeof(Bool_t));
    1244           0 :   }
    1245             :   //
    1246           0 :   int binv = (tstamp-fTMin)/fDeltaTVD; // time stamp provided: query for specific time bin
    1247           0 :   if (tstamp>0) {
    1248           0 :     if (binv>=0 && binv<nBinStat) return binStat[binv];
    1249           0 :     return kTRUE; // this should not happen normally
    1250             :   }
    1251             :   //   
    1252             :   // query for the whole run
    1253             :   int nHoles = 0, nChecked = 0;
    1254           0 :   int nbinsT = fTracksRate->GetNbinsX();
    1255           0 :   int nbinsE = fEvRateH->GetNbinsX();
    1256           0 :   int ntrCumul[nbinsT+2], sumNtr=0;
    1257           0 :   int nevCumul[nbinsE+2], sumNev=0;
    1258           0 :   ntrCumul[0] = nevCumul[0] = 0;
    1259           0 :   for (int ib=1;ib<=nbinsT;ib++) ntrCumul[ib] = (sumNtr += fTracksRate->GetBinContent(ib));
    1260           0 :   for (int ib=1;ib<=nbinsE;ib++) nevCumul[ib] = (sumNev += fEvRateH->GetBinContent(ib));
    1261           0 :   ntrCumul[nbinsT+1] = sumNtr;
    1262           0 :   nevCumul[nbinsE+1] = sumNev;
    1263             :   //
    1264             :   // mean number of tracks expected per tested bin in full stat
    1265           0 :   float nexpTracksAv = fEstTracksPerEvent*fNEvTot*fDeltaTVD/(fTMax-fTMin);
    1266             :   int longestEmpty=0,prevEmpty=0;
    1267           0 :   for (int ts=fTMin;ts<fTMax-fDeltaTVD;ts+=fDeltaTVD) {
    1268           0 :     int bminT = fTracksRate->FindBin(ts);
    1269           0 :     int bmaxT = fTracksRate->FindBin(ts+fDeltaTVD);
    1270           0 :     int bminE = fEvRateH->FindBin(ts);
    1271           0 :     int bmaxE = fEvRateH->FindBin(ts+fDeltaTVD);
    1272           0 :     int ntr = ntrCumul[bmaxT]-ntrCumul[bminT];
    1273           0 :     int binv = (ts+1-fTMin)/fDeltaTVD;
    1274           0 :     nChecked++;
    1275           0 :     if (ntr>fMinTracksPerVDBin) {
    1276           0 :       binStat[binv] = kTRUE; // flag complete bin
    1277           0 :       if (prevEmpty>longestEmpty) longestEmpty = prevEmpty;
    1278             :       prevEmpty = 0; // reset empty segment counter
    1279           0 :       continue;
    1280             :     }
    1281             :     // do we expect enough tracks in this time period?
    1282           0 :     int nexpTracks = (nevCumul[bmaxE]-nevCumul[bminE])*fEstTracksPerEvent;
    1283             :     // declare stat insufficient only if we expect enough tracks there
    1284           0 :     if (nexpTracks>fMinTracksPerVDBin && nexpTracks>nexpTracksAv/2 && ntr<fMinTracksPerVDBin/2) {
    1285           0 :       nHoles++;
    1286           0 :       prevEmpty += fDeltaTVD;
    1287           0 :     }
    1288           0 :     else binStat[binv] = kTRUE; // flag complete bin, since this bin is depleted on event level
    1289           0 :   }
    1290           0 :   if (prevEmpty>longestEmpty) longestEmpty = prevEmpty;
    1291           0 :   AliInfoF("%d bins out %d checked got enough stat., longest empty segment: %ds",
    1292             :            nChecked-nHoles,nChecked,longestEmpty);
    1293           0 :   if (nChecked && nHoles<maxHolesFrac*nChecked && longestEmpty<fSigmaTVD*0.75) return kTRUE;
    1294           0 :   return kFALSE;
    1295           0 : }
    1296             : 
    1297             : //________________________________________________
    1298             : void AliTPCDcalibRes::FillDriftResidualsTrees()
    1299             : {
    1300             :   // fill local trees for vdrift calibration
    1301           0 :   fDTV.t = fTimeStamp;
    1302           0 :   for (int icl=fNCl;icl--;) {
    1303           0 :     if (fArrR[icl]<kInvalidR) continue; // rejected outlier
    1304           0 :     Bool_t isCside = ((fArrSectID[icl]/kNSect)&0x1);
    1305           0 :     fDTV.side  = isCside ? -1:1;
    1306           0 :     fDTV.dz    = fArrDZ[icl];
    1307           0 :     fDTV.drift = kZLim[isCside] - fDTV.side*fArrZCl[icl];
    1308           0 :     fDTV.ylab  = fArrR[icl]*TMath::Sin(fArrPhi[icl]);
    1309           0 :     fDTV.r     = fArrR[icl];
    1310             :     // 
    1311           0 :     fTmpTree[0]->Fill();
    1312             :   }
    1313           0 :   if (fTracksRate) fTracksRate->Fill(fTimeStamp); // register track time
    1314             :   //
    1315           0 : }
    1316             : 
    1317             : //________________________________________________
    1318             : void AliTPCDcalibRes::FillLocalResidualsTrees()
    1319             : {
    1320             :   // fill local trees with binned data
    1321           0 :   float voxVars[kVoxHDim]={0}; // voxel variables (unbinned)
    1322           0 :   for (int icl=fNCl;icl--;) {
    1323           0 :     if (fArrX[icl]<kInvalidR) continue; // rejected outlier
    1324           0 :     int sectID = fArrSectID[icl]; // 0-35 numbering
    1325             :     // 
    1326             :     // calculate voxel variables and bins
    1327             :     // 
    1328           0 :     if (!FindVoxelBin(sectID, fArrX[icl], fArrYCl[icl], fArrZCl[icl], fDTS.bvox, voxVars)) continue;    
    1329           0 :     fDTS.dy   = fArrDY[icl];
    1330           0 :     fDTS.dz   = fArrDZ[icl];
    1331           0 :     fDTS.tgSlp = fArrTgSlp[icl];
    1332             :     //
    1333           0 :     fTmpTree[sectID]->Fill();
    1334             :     //
    1335             :     // fill statistics on distribution within the voxel, last dimension, kVoxV is for Nentries
    1336           0 :     ULong64_t binToFill = GetBin2Fill(fDTS.bvox,kVoxV); // bin of sector stat histo
    1337           0 :     float &binEntries = fArrNDStat[sectID]->At(binToFill); // entries in the voxel
    1338           0 :     float oldEntries  = binEntries++;
    1339           0 :     float norm        = 1.f/binEntries;
    1340           0 :     for (int iv=kVoxDim;iv--;) {
    1341           0 :       float &mean = fArrNDStat[sectID]->At(binToFill+iv-kVoxV);
    1342           0 :       mean = ( mean*oldEntries + voxVars[iv]) * norm; // account new bin entry in averages calculation
    1343             :     }
    1344             :     //
    1345           0 :   } // loop over clusters
    1346             :   //
    1347           0 :   if (fTracksRate) fTracksRate->Fill(fTimeStamp); // register track time
    1348             :   //
    1349           0 : }
    1350             : 
    1351             : //________________________________________________
    1352             : void AliTPCDcalibRes::FillCorrectedResiduals()
    1353             : {
    1354             :   // fill local trees result of closure test: corrected distortions
    1355             :   
    1356           0 :   float voxVars[kVoxHDim]={0}; // voxel variables (unbinned)
    1357           0 :   fDTC.t = fTimeStamp;
    1358           0 :   fDTC.q2pt   = fQ2Pt;
    1359           0 :   fDTC.tgLam  = fTgLam;
    1360             :   //
    1361           0 :   for (int icl=fNCl;icl--;) {
    1362           0 :     if (fArrX[icl]<kInvalidR) continue; // rejected outlier
    1363           0 :     int sectID = fArrSectID[icl]; // 0-35 numbering
    1364             :     // 
    1365             :     // extract correction
    1366             :     // calculate voxel variables and bins
    1367           0 :     if (!FindVoxelBin(sectID,fArrX[icl], fArrYCl[icl], fArrZCl[icl], fDTC.bvox, voxVars)) continue;    
    1368           0 :     int row159 = GetRowID(fArrX[icl]);
    1369           0 :     if (row159<0) continue;
    1370           0 :     float corr[3];
    1371             : 
    1372           0 :     fChebCorr->Eval(sectID, row159, fArrYCl[icl]/fArrX[icl], fArrZCl[icl]/fArrX[icl], corr);
    1373             :     // 
    1374           0 :     fDTC.dyR = fArrDY[icl];
    1375           0 :     fDTC.dzR = fArrDZ[icl];
    1376             : 
    1377           0 :     fDTC.dyC = fArrDY[icl] - (corr[kResY]-corr[kResX]*fArrTgSlp[icl]);
    1378           0 :     fDTC.dzC = fArrDZ[icl] - (corr[kResZ]-corr[kResX]*fTgLam); // we evaluate at pad-row
    1379             : 
    1380           0 :     fDTC.tgSlp  = fArrTgSlp[icl];
    1381           0 :     fDTC.x      = fArrX[icl];
    1382           0 :     fDTC.y      = fArrYCl[icl];
    1383           0 :     fDTC.z      = fArrZCl[icl];
    1384             :     //
    1385           0 :     fTmpTree[sectID]->Fill();
    1386             :     //
    1387           0 :   } // loop over clusters
    1388           0 : }
    1389             : 
    1390             : //________________________________________________
    1391             : void AliTPCDcalibRes::CreateLocalResidualsTrees(int mode)
    1392             : {
    1393             :   // temporary trees for local delta's storage
    1394             :   //
    1395           0 :   static dts_t *dtsP = &fDTS;
    1396           0 :   static dtc_t *dtcP = &fDTC;
    1397           0 :   static dtv_t *dtvP = &fDTV;
    1398           0 :   TString namef;
    1399           0 :   if (mode==kVDriftCalibMode) {
    1400           0 :     namef = Form("%s.root",kDriftResFileName);
    1401           0 :     fTmpFile[0] = TFile::Open(namef.Data(),"recreate");
    1402           0 :     fTmpTree[0] = new TTree("resdrift","");
    1403           0 :     fTmpTree[0]->Branch("dtv", &dtvP);
    1404             :   }
    1405           0 :   else if (mode==kDistExtractMode||mode==kDistClosureTestMode) {    
    1406           0 :     for (int is=0;is<kNSect2;is++) {
    1407           0 :       if      (mode==kDistExtractMode)         namef = Form("%s%d.root",kLocalResFileName,is);
    1408           0 :       else /*if (mode==kDistClosureTestMode)*/ namef = Form("%s%d.root",kClosureTestFileName,is);
    1409           0 :       fTmpFile[is] = TFile::Open(namef.Data(),"recreate");
    1410           0 :       fTmpTree[is] = new TTree(Form("ts%d",is),"");
    1411             :       //
    1412           0 :       if (mode==kDistExtractMode) {
    1413           0 :         fTmpTree[is]->Branch("dts", &dtsP);
    1414             :         //fTmpTree[is]->SetAutoFlush(150000);
    1415             :         //
    1416           0 :         fStatHist[is] = CreateVoxelStatHisto(is);
    1417           0 :         fArrNDStat[is] = (TNDArrayT<float>*)&fStatHist[is]->GetArray();
    1418           0 :       }
    1419           0 :       else if (mode==kDistClosureTestMode) {
    1420           0 :         fTmpTree[is]->Branch("dtc", &dtcP);
    1421             :       }
    1422             :     }
    1423           0 :   }
    1424           0 :   else AliFatalF("Unknown mode %d",mode);
    1425             :   //
    1426           0 : }
    1427             : 
    1428             : //________________________________________________
    1429             : void AliTPCDcalibRes::CloseLocalResidualsTrees(int /*mode*/)
    1430             : {
    1431             :   // close trees for local delta's storage
    1432             :   //
    1433           0 :   for (int is=0;is<kNSect2;is++) {
    1434           0 :     if (!fTmpFile[is]) continue;
    1435           0 :     fTmpFile[is]->cd();
    1436           0 :     fTmpTree[is]->Write("", TObject::kOverwrite);
    1437           0 :     delete fTmpTree[is];
    1438           0 :     fTmpTree[is] = 0;
    1439           0 :     fTmpFile[is]->Close();
    1440           0 :     delete fTmpFile[is];
    1441           0 :     fTmpFile[is] = 0;
    1442           0 :   }
    1443             :   //
    1444           0 : }
    1445             : 
    1446             : //__________________________________________________________________________________
    1447             : Bool_t AliTPCDcalibRes::CompareToHelix(float *resHelixY, float *resHelixZ)
    1448             : {
    1449             :   // compare track to helix, refit q/pt and tgLambda and build array of tg(slope) at pad-rows
    1450             :   const double kEps = 1e-12;
    1451           0 :   float xlab[kNPadRows],ylab[kNPadRows],spath[kNPadRows]; // lab X,Y rotated to for sectort of 1st cluster
    1452             :   // fill lab coordinates
    1453           0 :   float crv = TMath::Abs(fQ2Pt*fBz*0.299792458e-3f), cs,sn;
    1454           0 :   int sectPrev=-1,sect0 = fArrSectID[0]%kNSect; // align to the sector of 1st point
    1455           0 :   float phiSect = (sect0+0.5)*20*TMath::DegToRad();
    1456           0 :   double sna = TMath::Sin(phiSect), csa = TMath::Cos(phiSect);
    1457             :   //
    1458           0 :   spath[0] = 0.f;
    1459           0 :   for (int ip=0;ip<fNCl;ip++) {
    1460           0 :     cs = TMath::Cos(fArrPhi[ip]-phiSect);
    1461           0 :     sn = TMath::Sin(fArrPhi[ip]-phiSect);
    1462           0 :     xlab[ip] = fArrR[ip]*cs - fArrDY[ip]*sn;
    1463           0 :     ylab[ip] = fArrDY[ip]*cs + fArrR[ip]*sn;
    1464           0 :     if (ip) {
    1465           0 :       float dx = xlab[ip]-xlab[ip-1];
    1466           0 :       float dy = ylab[ip]-ylab[ip-1];
    1467           0 :       float ds2 = dx*dx+dy*dy;
    1468           0 :       float ds  = TMath::Sqrt(ds2); // circular path
    1469           0 :       if (ds*crv>0.05) { 
    1470             :         // account for the arc-chord difference as 1st 2 terms of asin expansion        
    1471           0 :         ds *= (1.f+ds2*crv*crv/24.f);
    1472           0 :       }
    1473           0 :       spath[ip] = spath[ip-1]+ds;
    1474           0 :     }
    1475             :   }
    1476           0 :   double xcSec=0,ycSec=0,xc=0,yc=0,r=0;
    1477           0 :   FitCircle(fNCl,xlab,ylab,xcSec,ycSec,r,resHelixY);
    1478             :   // determine qurvature
    1479           0 :   float phi0 = TMath::ATan2(ylab[0],xlab[0]);
    1480           0 :   if (phi0<0) phi0 += TMath::Pi()*2;
    1481           0 :   float phi1 = TMath::ATan2(ylab[fNCl-1],xlab[fNCl-1]);
    1482           0 :   if (phi1<0) phi1 += TMath::Pi()*2;
    1483           0 :   float dphi = phi1-phi0;
    1484             :   int curvSign = 1;
    1485           0 :   if (dphi>0) {
    1486           0 :     if (dphi<TMath::Pi()) curvSign = -1; // clockwise, no 2pi-0 crossing
    1487             :   }
    1488           0 :   else if (dphi<-TMath::Pi()) curvSign = -1; // clockwise, 2pi-0 crossing
    1489             :   //
    1490           0 :   fQ2Pt = curvSign/(r*fBz*0.299792458e-3f);
    1491             :   //
    1492             :   // calculate circle coordinates in the lab frame
    1493           0 :   xc = xcSec*csa - ycSec*sna;
    1494           0 :   yc = ycSec*csa + xcSec*sna;
    1495             :   //
    1496           0 :   float pol1z[2],pol1zE[4] ;
    1497           0 :   Bool_t resfZ = FitPoly1(spath, fArrZTr, 0, fNCl, pol1z, pol1zE);
    1498             :   //
    1499           0 :   fTgLam = pol1z[1]; // new tg. lambda
    1500             :   // extract deviations wrt helical fit and fill track slopes in sector frame
    1501             :   float hmnY=1e9,hmxY=-1e9,hmnZ=1e9,hmxZ=-1e9;
    1502             : 
    1503           0 :   for (int ip=0;ip<fNCl;ip++) {
    1504           0 :     float val = fArrZTr[ip] - (pol1z[0]+spath[ip]*pol1z[1]);
    1505           0 :     resHelixZ[ip] = val;
    1506           0 :     if (val<hmnZ) hmnZ = val;
    1507           0 :     if (val>hmxZ) hmxZ = val;
    1508             :     //    
    1509           0 :     val = resHelixY[ip];
    1510           0 :     if (val<hmnY) hmnY = val;
    1511           0 :     if (val>hmxY) hmxY = val;
    1512             :     //  
    1513           0 :     int sect = fArrSectID[ip]%kNSect;
    1514           0 :     if (sect!=sect0) {
    1515             :       sect0 = sect;
    1516           0 :       phiSect = (0.5f + sect)*kSecDPhi;
    1517           0 :       sna = TMath::Sin(phiSect);
    1518           0 :       csa = TMath::Cos(phiSect);
    1519           0 :       xcSec = xc*csa + yc*sna; // recalculate circle center in the sector frame
    1520           0 :     }
    1521             :     // find intersection of the circle with the padrow
    1522             :     // 1) equation of circle in lab: x=xc+r*cos(tau), y=yc+r*sin(tau)
    1523             :     // 2) equation of circle in sector frame: 
    1524             :     //    x=xc'+R*cos(tau-alpSect), y=yc'+R*sin(tau-alpSect)
    1525             :     //    with xc'=xc*cos(-alp)-yc*sin(-alp); yc'=yc*cos(-alp)+xc*sin(-alp)
    1526             :     // The circle and padrow at X cross at cos(tau) = (X-xc*csa+yc*sna)/R
    1527             :     // Hence the derivative of y vs x in sector frame:
    1528           0 :     cs = TMath::Cos(fArrPhi[ip]-phiSect);
    1529           0 :     double xRow = fArrR[ip]*cs; 
    1530           0 :     double cstalp = (xRow - xcSec)/r;
    1531           0 :     if (TMath::Abs(cstalp)>1.-kEps) { // track cannot reach this padrow
    1532           0 :       cstalp = TMath::Sign(1.-kEps,cstalp);
    1533           0 :     }
    1534             :     // and the slope in sector frame is +-1/tg(acos(cstalp)) = +-cstalp/sqrt(1-cstalp^2)
    1535             :     // The sign is defined by the fact that in B+ the slope of q- should increase with X.
    1536             :     // Since the derivative of cstalp/sqrt(1-cstalp^2) on X is positive, just look on qB
    1537           0 :     fArrTgSlp[ip] = cstalp/TMath::Sqrt((1.-cstalp)*(1.+cstalp));
    1538           0 :     if (fQ2Pt*fBz>0) fArrTgSlp[ip] = -fArrTgSlp[ip];
    1539             :   }
    1540             :   //
    1541             :   //  if (TMath::Abs(hmxY-hmnY)>fMaxDevYHelix || TMath::Abs(hmxZ-hmnZ)>fMaxDevZHelix)
    1542             :   //    printf("MinMax%d: %e %e %e %e\n",evID,hmnY,hmxY,hmnZ,hmxZ);
    1543           0 :   return TMath::Abs(hmxY-hmnY)<fMaxDevYHelix && TMath::Abs(hmxZ-hmnZ)<fMaxDevZHelix;
    1544           0 : }
    1545             : 
    1546             : //________________________________________________
    1547             : void AliTPCDcalibRes::ClosureTest()
    1548             : {
    1549             :   // correct distortions
    1550           0 :   TStopwatch sw;
    1551           0 :   sw.Start();
    1552           0 :   if (!fChebCorr) {
    1553           0 :     AliError("Chebyshev correction object was not created, cannot run closure test");
    1554           0 :     return;
    1555             :   }
    1556           0 :   CollectData(kDistClosureTestMode);
    1557           0 :   sw.Stop();
    1558           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
    1559             :   //
    1560           0 : }
    1561             : 
    1562             : //________________________________________________
    1563             : void AliTPCDcalibRes::ProcessResiduals()
    1564             : {
    1565             :   // project local trees, extract distortions
    1566           0 :   if (!fInitDone) Init(); //{AliError("Init not done"); return;}
    1567           0 :   LoadStatHistos();
    1568           0 :   AliSysInfo::AddStamp("ProcResid",0,0,0,0);
    1569             :   //
    1570           0 :   for (int is=0;is<kNSect2;is++) ProcessSectorResiduals(is);
    1571             :   //
    1572           0 :   AliSysInfo::AddStamp("ProcResid",1,0,0,0);
    1573             :   //
    1574           0 : }
    1575             : 
    1576             : //________________________________________________
    1577             : void AliTPCDcalibRes::ProcessDispersions()
    1578             : {
    1579             :   // extract distortions of corrected Y residuals ||| DEPRECATED
    1580           0 :   if (!fInitDone) Init(); //{AliError("Init not done"); return;}
    1581             :   //
    1582           0 :   LoadStatHistos();
    1583           0 :   for (int is=0;is<kNSect2;is++) {
    1584           0 :     ProcessSectorDispersions(is);
    1585           0 :     if (fDeleteSectorTrees) {
    1586           0 :       TString sectFileName = Form("%s%d.root",kLocalResFileName,is);
    1587           0 :       AliInfoF("Deleting %s",sectFileName.Data());
    1588           0 :       unlink(sectFileName.Data());
    1589           0 :     }
    1590             :   }
    1591             :   //
    1592           0 : }
    1593             : 
    1594             : //________________________________________________
    1595             : void AliTPCDcalibRes::ProcessSectorDispersions(int is)
    1596             : {
    1597             :   // extract dispersion of corrected residuals ||| DEPRECATED
    1598             :   const float kEps = 1e-6;
    1599             : 
    1600           0 :   if (!fInitDone) {AliError("Init not done"); return;}
    1601           0 :   TStopwatch sw;  sw.Start();
    1602           0 :   AliSysInfo::AddStamp("ProcessSectorDispersions",is,0,0,0);
    1603             : 
    1604           0 :   TString sectFileName = Form("%s%d.root",kLocalResFileName,is);
    1605           0 :   TFile* sectFile = TFile::Open(sectFileName.Data());
    1606           0 :   if (!sectFile) AliFatalF("file %s not found",sectFileName.Data());
    1607           0 :   TString treeName = Form("ts%d",is);
    1608           0 :   TTree *sectTree = (TTree*) sectFile->Get(treeName.Data());
    1609           0 :   if (!sectTree) AliFatalF("tree %s is not found in file %s",treeName.Data(),sectFileName.Data());
    1610             :   //
    1611           0 :   dts_t *dtsP = &fDTS; 
    1612           0 :   sectTree->SetBranchAddress("dts",&dtsP);
    1613           0 :   int npoints = sectTree->GetEntries();
    1614           0 :   if (!npoints) {
    1615           0 :     AliWarningF("No entries for sector %d",is);
    1616           0 :     delete sectTree;
    1617           0 :     sectFile->Close(); // to reconsider: reuse the file
    1618           0 :     delete sectFile;
    1619           0 :     return;
    1620             :   }
    1621           0 :   Short_t *resYArr = new Short_t[npoints];
    1622           0 :   Short_t *tgslArr = new Short_t[npoints];
    1623           0 :   UShort_t *binArr = new UShort_t[npoints];
    1624           0 :   Int_t* index = new Int_t[npoints];
    1625           0 :   TArrayF dya(1000),tga(1000);//, dza(1000),
    1626           0 :   float *dy = dya.GetArray(), *tg = tga.GetArray();//, *dz = dza.GetArray();
    1627             :   int nacc = 0;
    1628           0 :   bres_t* sectData = fSectGVoxRes[is];
    1629           0 :   for (int ie=0;ie<npoints;ie++) {
    1630           0 :     sectTree->GetEntry(ie);
    1631           0 :     if (TMath::Abs(fDTS.tgSlp)>=kMaxTgSlp) continue;
    1632           0 :     resYArr[nacc] = Short_t(fDTS.dy*0x7fff/kMaxResid);
    1633           0 :     tgslArr[nacc] = Short_t(fDTS.tgSlp*0x7fff/kMaxTgSlp);
    1634           0 :     binArr[nacc] = GetVoxGBin(fDTS.bvox);
    1635           0 :     nacc++;
    1636           0 :   }
    1637           0 :   TMath::Sort(nacc, binArr, index, kFALSE); // sort in voxel increasing order
    1638             :   UShort_t curBin = 0xffff;
    1639           0 :   UChar_t bvox[kVoxDim];
    1640             :   int nproc = 0, npBin = 0;
    1641           0 :   while (nproc<nacc) {
    1642           0 :     int ip = index[nproc++];
    1643           0 :     if (curBin!=binArr[ip]) {
    1644           0 :       if (npBin) {
    1645           0 :         bres_t& resVox = sectData[curBin];
    1646           0 :         GBin2Vox(curBin,resVox.bvox);  // parse voxel
    1647           0 :         ProcessVoxelDispersions(npBin,tg,dy,resVox);    
    1648           0 :       }
    1649           0 :       curBin = binArr[ip];
    1650             :       npBin = 0;
    1651           0 :     }
    1652           0 :     if (npBin==dya.GetSize()) {
    1653           0 :       dya.Set(100+npBin); dy = dya.GetArray();
    1654           0 :       tga.Set(100+npBin); tg = tga.GetArray();
    1655           0 :     }
    1656           0 :     dy[npBin] = resYArr[ip]*kMaxResid/0x7fff;
    1657           0 :     tg[npBin] = tgslArr[ip]*kMaxTgSlp/0x7fff;
    1658           0 :     npBin++;
    1659             :   }
    1660           0 :   if (npBin) {
    1661           0 :     bres_t& resVox = sectData[curBin];
    1662           0 :     GBin2Vox(curBin,resVox.bvox);  // parse voxel
    1663           0 :     ProcessVoxelDispersions(npBin,tg,dy,resVox);
    1664           0 :   }
    1665             :   //
    1666           0 :   delete[] binArr;
    1667           0 :   delete[] resYArr;
    1668           0 :   delete[] tgslArr;
    1669           0 :   delete[] index;
    1670             :   //
    1671           0 :   delete sectTree;
    1672           0 :   sectFile->Close(); // to reconsider: reuse the file
    1673           0 :   delete sectFile;
    1674             :   //
    1675             :   // now smooth the dispersion
    1676           0 :   for (bvox[kVoxX]=0;bvox[kVoxX]<fNXBins;bvox[kVoxX]++) { 
    1677           0 :     if (GetXBinIgnored(is,bvox[kVoxX])) continue;
    1678           0 :     for (bvox[kVoxZ]=0;bvox[kVoxZ]<fNZ2XBins;bvox[kVoxZ]++) {
    1679           0 :       for (bvox[kVoxF]=0;bvox[kVoxF]<fNY2XBins;bvox[kVoxF]++) {
    1680           0 :         int binGlo = GetVoxGBin(bvox);
    1681           0 :         bres_t *voxRes = &sectData[binGlo];
    1682           0 :         Bool_t res = GetSmoothEstimate(is,voxRes->stat[kVoxX],voxRes->stat[kVoxF],voxRes->stat[kVoxZ],
    1683           0 :                                        BIT(kResD), voxRes->DS);
    1684             :       }
    1685             :     }
    1686             :   }
    1687             :   //
    1688           0 :   sw.Stop(); 
    1689           0 :   AliInfoF("Sector%2d | timing: real: %.3f cpu: %.3f",is, sw.RealTime(), sw.CpuTime());
    1690           0 :   AliSysInfo::AddStamp("ProcessSectorDispersions",1,0,0,0);
    1691             :   //
    1692           0 : }
    1693             : 
    1694             : //_________________________________________________
    1695             : void AliTPCDcalibRes::ProcessSectorResiduals(int is)
    1696             : {
    1697             :   // process residuals for single sector staring from local binned per-sector trees
    1698             :   //
    1699             :   const int kMaxPnt = 30000000; // max points per sector to accept
    1700           0 :   TStopwatch sw;  sw.Start();
    1701           0 :   AliSysInfo::AddStamp("ProcSectRes",is,0,0,0);
    1702             :   //
    1703           0 :   fNSmoothingFailedBins[is] = 0;
    1704             :   //
    1705           0 :   TString sectFileName = Form("%s%d.root",kLocalResFileName,is);
    1706           0 :   TFile* sectFile = TFile::Open(sectFileName.Data());
    1707           0 :   if (!sectFile) AliFatalF("file %s not found",sectFileName.Data());
    1708           0 :   TString treeName = Form("ts%d",is);
    1709           0 :   TTree *sectTree = (TTree*) sectFile->Get(treeName.Data());
    1710           0 :   if (!sectTree) AliFatalF("tree %s is not found in file %s",treeName.Data(),sectFileName.Data());
    1711             :   //
    1712           0 :   if (fSectGVoxRes[is]) delete[] fSectGVoxRes[is];
    1713           0 :   fSectGVoxRes[is] = new bres_t[fNGVoxPerSector]; // here we keep main result
    1714             :   bres_t*  sectData = fSectGVoxRes[is];
    1715             :   // by default set the COG estimates to bin center
    1716           0 :   for (int ix=0;ix<fNXBins;ix++) {
    1717           0 :     for (int ip=0;ip<fNY2XBins;ip++) {
    1718           0 :       for (int iz=0;iz<fNZ2XBins;iz++) {  // extract line in z
    1719           0 :         int binGlo = GetVoxGBin(ix,ip,iz);
    1720           0 :         bres_t &resVox = sectData[binGlo];
    1721           0 :         resVox.bvox[kVoxX] = ix;
    1722           0 :         resVox.bvox[kVoxF] = ip;
    1723           0 :         resVox.bvox[kVoxZ] = iz;        
    1724           0 :         resVox.bsec = is;
    1725           0 :         GetVoxelCoordinates(resVox.bsec,resVox.bvox[kVoxX],resVox.bvox[kVoxF],resVox.bvox[kVoxZ],
    1726           0 :                             resVox.stat[kVoxX],resVox.stat[kVoxF],resVox.stat[kVoxZ]);
    1727             :       }
    1728             :     } 
    1729             :   }
    1730             :   //
    1731           0 :   dts_t *dtsP = &fDTS; 
    1732           0 :   sectTree->SetBranchAddress("dts",&dtsP);
    1733           0 :   int npoints = sectTree->GetEntries();
    1734           0 :   if (!npoints) {
    1735           0 :     AliWarningF("No entries for sector %d, masking all rows",is);
    1736           0 :     for (int ix=fNXBins;ix--;) SetXBinIgnored(is,ix);
    1737           0 :     delete sectTree;
    1738           0 :     sectFile->Close(); // to reconsider: reuse the file
    1739           0 :     delete sectFile;
    1740           0 :     return;
    1741             :   }
    1742           0 :   if (npoints>kMaxPnt) npoints = kMaxPnt;
    1743           0 :   sw.Stop();
    1744           0 :   AliInfoF("Sector%2d. Extracted %d points of unbinned data. Timing: real: %.3f cpu: %.3f",
    1745             :            is, npoints, sw.RealTime(), sw.CpuTime());
    1746           0 :   sw.Start(kFALSE);
    1747             :   //
    1748           0 :   Short_t *resYArr = new Short_t[npoints];
    1749           0 :   Short_t *resZArr = new Short_t[npoints];
    1750           0 :   Short_t *tgslArr = new Short_t[npoints];
    1751           0 :   UShort_t *binArr = new UShort_t[npoints];
    1752           0 :   Int_t* index = new Int_t[npoints];
    1753           0 :   TArrayF dya(1000),dza(1000),tga(1000);
    1754           0 :   float *dy = dya.GetArray(), *dz = dza.GetArray(), *tg = tga.GetArray();
    1755             :   int nacc = 0;
    1756           0 :   for (int ie=0;ie<npoints;ie++) {
    1757           0 :     sectTree->GetEntry(ie);
    1758           0 :     if (TMath::Abs(fDTS.tgSlp)>=kMaxTgSlp) continue;
    1759           0 :     resYArr[nacc] = Short_t(fDTS.dy*0x7fff/kMaxResid);
    1760           0 :     resZArr[nacc] = Short_t(fDTS.dz*0x7fff/kMaxResid);
    1761           0 :     tgslArr[nacc] = Short_t(fDTS.tgSlp*0x7fff/kMaxTgSlp);
    1762           0 :     binArr[nacc] = GetVoxGBin(fDTS.bvox);
    1763           0 :     nacc++;
    1764           0 :   }
    1765             :   //
    1766           0 :   delete sectTree;
    1767           0 :   sectFile->Close(); // to reconsider: reuse the file
    1768           0 :   delete sectFile;
    1769             :   //
    1770           0 :   TMath::Sort(nacc, binArr, index, kFALSE); // sort in voxel increasing order
    1771             :   UShort_t curBin = 0xffff;
    1772           0 :   UChar_t bvox[kVoxDim];
    1773             :   int nproc = 0, npBin = 0;
    1774           0 :   while (nproc<nacc) {
    1775           0 :     int ip = index[nproc++];
    1776           0 :     if (curBin!=binArr[ip]) {
    1777           0 :       if (npBin) {
    1778           0 :         bres_t& resVox = sectData[curBin];
    1779           0 :         GBin2Vox(curBin,resVox.bvox);  // parse voxel
    1780           0 :         ProcessVoxelResiduals(npBin,tg,dy,dz,resVox);   
    1781           0 :       }
    1782           0 :       curBin = binArr[ip];
    1783             :       npBin = 0;
    1784           0 :     }
    1785           0 :     if (npBin==dya.GetSize()) {
    1786           0 :       dya.Set(100+npBin); dy = dya.GetArray();
    1787           0 :       dza.Set(100+npBin); dz = dza.GetArray();
    1788           0 :       tga.Set(100+npBin); tg = tga.GetArray();
    1789           0 :     }
    1790           0 :     dy[npBin] = resYArr[ip]*kMaxResid/0x7fff;
    1791           0 :     dz[npBin] = resZArr[ip]*kMaxResid/0x7fff;
    1792           0 :     tg[npBin] = tgslArr[ip]*kMaxTgSlp/0x7fff;
    1793           0 :     npBin++;
    1794             :   }
    1795           0 :   if (npBin) {
    1796           0 :     bres_t &resVox = sectData[curBin];
    1797           0 :     GBin2Vox(curBin,resVox.bvox);  // parse voxel
    1798           0 :     ProcessVoxelResiduals(npBin,tg,dy,dz,resVox);
    1799           0 :   }
    1800             :   //
    1801           0 :   sw.Stop();
    1802           0 :   AliInfoF("Sector%2d. Extracted residuals. Timing: real: %.3f cpu: %.3f",
    1803             :            is, sw.RealTime(), sw.CpuTime());
    1804           0 :   sw.Start(kFALSE);
    1805             :   
    1806           0 :   int nrowOK = ValidateVoxels(is);
    1807           0 :   if (!nrowOK) AliWarningF("Sector%2d: all X-bins disabled, abandon smoothing",is);
    1808           0 :   else Smooth0(is);
    1809             :   //
    1810           0 :   sw.Stop();
    1811           0 :   AliInfoF("Sector%2d. Smoothed residuals. Timing: real: %.3f cpu: %.3f",
    1812             :            is, sw.RealTime(), sw.CpuTime());
    1813           0 :   sw.Start(kFALSE);
    1814             : 
    1815             :   // now process dispersions
    1816             :   curBin = 0xffff;
    1817             : 
    1818             :   nproc = 0;
    1819             :   npBin = 0;
    1820           0 :   while (nproc<nacc) {
    1821           0 :     int ip = index[nproc++];
    1822           0 :     if (curBin!=binArr[ip]) {
    1823           0 :       if (npBin) {
    1824           0 :         bres_t& resVox = sectData[curBin];
    1825           0 :         GBin2Vox(curBin,resVox.bvox);  // parse voxel
    1826           0 :         if (!GetXBinIgnored(is,resVox.bvox[kVoxX])) ProcessVoxelDispersions(npBin,tg,dy,resVox);        
    1827           0 :       }
    1828           0 :       curBin = binArr[ip];
    1829             :       npBin = 0;
    1830           0 :     }
    1831           0 :     if (npBin==dya.GetSize()) {
    1832           0 :       dya.Set(100+npBin); dy = dya.GetArray();
    1833           0 :       tga.Set(100+npBin); tg = tga.GetArray();
    1834           0 :     }
    1835           0 :     dy[npBin] = resYArr[ip]*kMaxResid/0x7fff;
    1836           0 :     tg[npBin] = tgslArr[ip]*kMaxTgSlp/0x7fff;
    1837           0 :     npBin++;
    1838             :   }
    1839           0 :   if (npBin) {
    1840           0 :     bres_t& resVox = sectData[curBin];
    1841           0 :     GBin2Vox(curBin,resVox.bvox);  // parse voxel
    1842           0 :     if (!GetXBinIgnored(is,resVox.bvox[kVoxX])) ProcessVoxelDispersions(npBin,tg,dy,resVox);
    1843           0 :   }
    1844             :   //
    1845             :   // now smooth the dispersion
    1846           0 :   for (bvox[kVoxX]=0;bvox[kVoxX]<fNXBins;bvox[kVoxX]++) { 
    1847           0 :     if (GetXBinIgnored(is,bvox[kVoxX])) continue;
    1848           0 :     for (bvox[kVoxZ]=0;bvox[kVoxZ]<fNZ2XBins;bvox[kVoxZ]++) {
    1849           0 :       for (bvox[kVoxF]=0;bvox[kVoxF]<fNY2XBins;bvox[kVoxF]++) {
    1850           0 :         int binGlo = GetVoxGBin(bvox);
    1851           0 :         bres_t *voxRes = &sectData[binGlo];
    1852           0 :         Bool_t res = GetSmoothEstimate(is,voxRes->stat[kVoxX],voxRes->stat[kVoxF],voxRes->stat[kVoxZ],
    1853           0 :                                        BIT(kResD), voxRes->DS);
    1854             :       }
    1855             :     }
    1856             :   }
    1857             : 
    1858           0 :   delete[] binArr;
    1859           0 :   delete[] resYArr;
    1860           0 :   delete[] resZArr;
    1861           0 :   delete[] tgslArr;
    1862           0 :   delete[] index;
    1863             :   //
    1864           0 :   sw.Stop(); 
    1865           0 :   AliInfoF("Sector%2d. Processed dispersion. Timing: real: %.3f cpu: %.3f",is, sw.RealTime(), sw.CpuTime());
    1866           0 :   AliSysInfo::AddStamp("ProcSectRes",is,1,0,0);
    1867             :   //
    1868           0 : }
    1869             : //________________________________________________
    1870             : void AliTPCDcalibRes::ReProcessResiduals()
    1871             : {
    1872             :   // reprocess residuals using raw voxel info filled from existing resVoxTree
    1873             :   // The raw data is already loaded from the tree
    1874           0 :   AliSysInfo::AddStamp("ReProcResid",0,0,0,0);
    1875           0 :   for (int is=0;is<kNSect2;is++) ReProcessSectorResiduals(is);
    1876           0 :   AliSysInfo::AddStamp("ReProcResid",1,0,0,0);
    1877           0 : }
    1878             : 
    1879             : //_________________________________________________
    1880             : void AliTPCDcalibRes::ReProcessSectorResiduals(int is)
    1881             : {
    1882             :   // Reprocess residuals for single sector filled from existing resVoxTree
    1883             :   // The raw data is already loaded from the tree
    1884             :   //
    1885           0 :   TStopwatch sw;  sw.Start();
    1886           0 :   AliSysInfo::AddStamp("RProcSectRes",is,0,0,0);
    1887             :   //
    1888           0 :   fNSmoothingFailedBins[is] = 0;
    1889           0 :   bres_t*  sectData = fSectGVoxRes[is];
    1890           0 :   if (!sectData) AliFatalF("No SectGVoxRes data for sector %d",is);
    1891             :   //
    1892           0 :   int nrowOK = ValidateVoxels(is);
    1893           0 :   if (!nrowOK) AliWarningF("Sector%2d: all X-bins disabled, abandon smoothing",is);
    1894           0 :   else Smooth0(is);
    1895             :   //
    1896           0 :   UChar_t bvox[kVoxDim];
    1897             :   // now smooth the dispersion
    1898           0 :   for (bvox[kVoxX]=0;bvox[kVoxX]<fNXBins;bvox[kVoxX]++) { 
    1899           0 :     if (GetXBinIgnored(is,bvox[kVoxX])) continue;
    1900           0 :     for (bvox[kVoxZ]=0;bvox[kVoxZ]<fNZ2XBins;bvox[kVoxZ]++) {
    1901           0 :       for (bvox[kVoxF]=0;bvox[kVoxF]<fNY2XBins;bvox[kVoxF]++) {
    1902           0 :         int binGlo = GetVoxGBin(bvox);
    1903           0 :         bres_t *voxRes = &sectData[binGlo];
    1904           0 :         Bool_t res = GetSmoothEstimate(is,voxRes->stat[kVoxX],voxRes->stat[kVoxF],voxRes->stat[kVoxZ],
    1905           0 :                                        BIT(kResD), voxRes->DS);
    1906             :       }
    1907             :     }
    1908             :   } 
    1909           0 :   sw.Stop(); 
    1910           0 :   AliInfoF("Sector%2d. Processed dispersion. Timing: real: %.3f cpu: %.3f",is, sw.RealTime(), sw.CpuTime());
    1911           0 :   AliSysInfo::AddStamp("ReProcSectRes",is,1,0,0);
    1912             :   //
    1913           0 : }
    1914             : 
    1915             : //_________________________________________________________
    1916             : Float_t AliTPCDcalibRes::FitPoly1Robust(int np, float* x, float* y, float* res, float* err, float ltmCut)
    1917             : {
    1918             :   // robust pol1 fit, modifies input arrays order
    1919           0 :   res[0] = res[1] = 0.f;
    1920           0 :   if (np<2) return -1;
    1921           0 :   TVectorF yres(7);
    1922           0 :   int *indY =  TStatToolkit::LTMUnbinned(np,y,yres,ltmCut);
    1923           0 :   if (!indY) return -1;
    1924             :   // rearrange used events in increasing order
    1925           0 :   TStatToolkit::Reorder(np,y,indY);
    1926           0 :   TStatToolkit::Reorder(np,x,indY);
    1927             :   //
    1928             :   // 1st fit to get crude slope
    1929           0 :   int npuse = TMath::Nint(yres[0]);
    1930           0 :   int offs =  TMath::Nint(yres[5]);
    1931             :   // use only entries selected by LTM for the fit
    1932           0 :   float a,b;
    1933           0 :   AliTPCDcalibRes::medFit(npuse, x+offs, y+offs, a, b, err);
    1934             :   //
    1935             :   // don't abuse stack
    1936           0 :   float *ycmHeap=0,ycmStack[np<kMaxOnStack ? np:1],*ycm=np<kMaxOnStack ? &ycmStack[0] : (ycmHeap=new float[np]);
    1937           0 :   int   *indcmHeap=0,indcmStack[np<kMaxOnStack ? np:1],*indcm=np<kMaxOnStack ? &indcmStack[0] : (indcmHeap=new int[np]);
    1938             :   //  
    1939           0 :   for (int i=np;i--;) ycm[i] = y[i]-(a+b*x[i]);
    1940           0 :   TMath::Sort(np,ycm,indcm,kFALSE);
    1941           0 :   TStatToolkit::Reorder(np,ycm,indcm);
    1942           0 :   TStatToolkit::Reorder(np,y,indcm); // we must keep the same order
    1943           0 :   TStatToolkit::Reorder(np,x,indcm);
    1944             :   //
    1945             :   // robust estimate of sigma after crude slope correction
    1946           0 :   float sigMAD = AliTPCDcalibRes::MAD2Sigma(npuse,ycm+offs);
    1947             :   // find LTM estimate matching to sigMAD, keaping at least given fraction
    1948           0 :   indY = AliTPCDcalibRes::LTMUnbinnedSig(np, ycm, yres, sigMAD,0.5,kTRUE);
    1949           0 :   delete[] ycmHeap;
    1950           0 :   delete[] indcmHeap;
    1951             :   //
    1952           0 :   if (!indY) return -1;
    1953             :   // final fit
    1954           0 :   npuse = TMath::Nint(yres[0]);
    1955           0 :   offs =  TMath::Nint(yres[5]);
    1956           0 :   AliTPCDcalibRes::medFit(npuse, x+offs, y+offs, a,b, err);
    1957           0 :   res[0] = a;
    1958           0 :   res[1] = b;
    1959           0 :   return sigMAD;
    1960           0 : }
    1961             : 
    1962             : //_________________________________________________
    1963             : void AliTPCDcalibRes::ProcessVoxelResiduals(int np, float* tg, float *dy, float *dz, bres_t& voxRes)
    1964             : {
    1965             :   // extract X,Y,Z distortions of the voxel
    1966           0 :   if (np<fMinEntriesVoxel) return;
    1967           0 :   TVectorF zres(7);
    1968           0 :   voxRes.flags = 0;
    1969           0 :   if (!TStatToolkit::LTMUnbinned(np,dz,zres,fLTMCut)) return; 
    1970             :   //
    1971           0 :   float ab[2],err[3];
    1972           0 :   float sigMAD = FitPoly1Robust(np,tg,dy,ab,err,fLTMCut);
    1973           0 :   if (sigMAD<0) return;
    1974           0 :   float corrErr = err[0]*err[2];
    1975           0 :   corrErr = corrErr>0 ? err[1]/TMath::Sqrt(corrErr) : -999;
    1976             :   //printf("N:%3d A:%+e B:%+e / %+e %+e %+e | %+e %+e / %+e %+e\n",np,a,b,err[0],err[1],err[2], zres[1],zres[2], zres[3],zres[4]);
    1977             :   //
    1978           0 :   voxRes.D[kResX] = -ab[1];
    1979           0 :   voxRes.D[kResY] = ab[0];
    1980           0 :   voxRes.D[kResZ] = zres[1];
    1981           0 :   voxRes.E[kResX] = TMath::Sqrt(err[2]);
    1982           0 :   voxRes.E[kResY] = TMath::Sqrt(err[0]);
    1983           0 :   voxRes.E[kResZ] = zres[4];
    1984           0 :   voxRes.EXYCorr  = corrErr;
    1985           0 :   voxRes.D[kResD] = voxRes.dYSigMAD = sigMAD; // later will be overriden by real dispersion
    1986           0 :   voxRes.dZSigLTM = zres[2];
    1987             :   //
    1988             :   // store the statistics
    1989           0 :   ULong64_t binStat = GetBin2Fill(voxRes.bvox,kVoxV);
    1990           0 :   voxRes.stat[kVoxV] = fArrNDStat[voxRes.bsec]->At(binStat);
    1991           0 :   for (int iv=kVoxDim;iv--;) voxRes.stat[iv] = fArrNDStat[voxRes.bsec]->At(binStat+iv-kVoxV);
    1992             :   //
    1993           0 :   voxRes.flags |= kDistDone;
    1994           0 : }
    1995             : 
    1996             : //_________________________________________________
    1997             : void AliTPCDcalibRes::ProcessVoxelDispersions(int np, const float* tg, float *dy, bres_t& voxRes)
    1998             : {
    1999             :   // extract Y (Z ignored at the moment) dispersions of the voxel
    2000             :   // correct Y distortions
    2001           0 :   if (np<2) return;
    2002           0 :   for (int i=np;i--;) dy[i] -= voxRes.DS[kResY] - voxRes.DS[kResX]*tg[i];
    2003           0 :   voxRes.D[kResD] = MAD2Sigma(np,dy);
    2004           0 :   voxRes.E[kResD] = voxRes.D[kResD]/TMath::Sqrt(2.*np); // a la gaussian RMS error, this is very crude
    2005           0 :   voxRes.flags |= kDispDone;
    2006             :   //
    2007           0 : }
    2008             : 
    2009             : //_____________________________________________________________________
    2010             : Double_t AliTPCDcalibRes::GetLogL(TH1F* histo, int bin0, int bin1, double &mu, double &sig, double &logL0)
    2011             : {
    2012             :   // Calculate log likelihood of normal distribution for the histo between boundaries 
    2013             :   // bin0 and bin for given mu and sigma assumption. Exact Poisson statistics is assumed
    2014             :   // Also the approximate "reference" log-likelihood logLO is calculated in the following way:
    2015             :   // if the Poisson prob. for given bin is "m", then the logL0 gets contribution for this bin
    2016             :   // log("reference probability"), which I define as a geometric mean of probabilities for
    2017             :   // observing [M] and [M]+1 entries if m is large: 
    2018             :   // P_ref = exp(-m)/m! M^m sqrt( m/(M+1) )
    2019             :   // -> ln(P_ref) = -(1/2+M)*ln(M/m) + M-m + 1/2 ln(M+1) - 1/2 ln(2 pi) -> -1/2 ln(2 pi m) for m>>1 (take m>5)
    2020             :   //                (precise up to 1/2 ln(2 pi m) term of Stirling formula
    2021             :   // or           = -m + m*log(m) - log( Gamma(1.+m) )                                     for m<~1
    2022             :   // 
    2023             :   // integral
    2024             :   const double kNuLarge = 5.0, kMinSig2BinH = 0.01;
    2025           0 :   double dxh = 0.5*histo->GetBinWidth(1);
    2026           0 :   if ((sig/dxh)<kMinSig2BinH) {
    2027           0 :     AliWarningClassF("Too small sigma %.4e is provided for bin width %.4e",sig,dxh);
    2028           0 :     logL0 = -1;
    2029           0 :     return -1e9;
    2030             :   }
    2031             :   double sum=0, sum1=0, sum2=0;
    2032             :   
    2033           0 :   for (int ib=bin0;ib<=bin1;ib++) {
    2034           0 :     double w = histo->GetBinContent(ib);
    2035           0 :     double x = histo->GetBinCenter(ib);
    2036           0 :     sum += w;
    2037           0 :     sum1 += w*x;
    2038           0 :     sum2 += w*x*x;
    2039             :   }  
    2040             :   //
    2041           0 :   double xb0 = histo->GetBinCenter(bin0)-dxh;
    2042           0 :   double xb1 = histo->GetBinCenter(bin1)+dxh;
    2043             :   //
    2044           0 :   if (sum<1e-6) {logL0 = -1e6; return -1e9;}
    2045           0 :   mu = sum1/sum;
    2046           0 :   sig = sum2/sum - mu*mu;
    2047           0 :   sig = TMath::Max(sig>0 ? TMath::Sqrt(sig) : 0.f, dxh/TMath::Sqrt(3)); // don't allow too small sigma
    2048             :   
    2049             :   //printf("Sample mu : %e sig: %e in %e %e\n",mu,sig,xb0,xb1);
    2050             : 
    2051             :   // estimated sig, mu are from the truncated sample, try to recover the truth
    2052           0 :   GetTruncNormMuSig(xb0,xb1, mu, sig);
    2053             :   //
    2054           0 :   xb0 -= mu;
    2055           0 :   xb1 -= mu;
    2056           0 :   double sqri2 = 1./(TMath::Sqrt(2.)*sig);
    2057             :   // normalization constant
    2058           0 :   double norm = 2.*sum / (TMath::Erf(xb1*sqri2) - TMath::Erf(xb0*sqri2));
    2059             :   //
    2060             :   //  printf("Norm: %e\n",norm);
    2061             :   // likelihood
    2062             :   double logL = 0;
    2063           0 :   logL0 = 0;
    2064             :   const double kMinExp = 1e-100;
    2065           0 :   for (int i=bin0;i<=bin1;i++) {
    2066           0 :     double x = histo->GetBinCenter(i)-mu;
    2067           0 :     double w = histo->GetBinContent(i);
    2068           0 :     xb0 = x-dxh;
    2069           0 :     xb1 = x+dxh;
    2070             :     // bin expectation: normal integral within the bin
    2071           0 :     double nu = 0.5*norm*(TMath::Erf(xb1*sqri2) - TMath::Erf(xb0*sqri2));  
    2072           0 :     if (nu<kMinExp) nu = kMinExp;
    2073           0 :     double logNFac = w<100 ? TMath::Log(TMath::Factorial(w)) : w*TMath::Log(w)-w + TMath::Log( sqrt(2*TMath::Pi()*w));
    2074           0 :     double logNu = TMath::Log(nu);
    2075           0 :     double logc = -nu + w*logNu - logNFac;  // contribution of this bin to log-likelihood
    2076           0 :     logL += logc;
    2077             :     // now get the reference contribution
    2078             :     double logc0 = 0;
    2079           0 :     if (nu>kNuLarge) logc0 = -0.5*TMath::Log(2.*TMath::Pi()*nu);
    2080             :     else {
    2081           0 :       logc0 = -nu + nu*logNu - TMath::Log( TMath::Gamma(1.+nu) );
    2082             :     }
    2083           0 :     logL0 += logc0;  // reference LL update
    2084             :     //printf("b: %d x:%+.2e nstd:%+.2e Exp:%e Obs:%e logc: %e logc0: %e\n",i,x,(x-mu)/sig, nu,w,logc, logc0);
    2085             : 
    2086             :   }
    2087             :   //  printf("LogL: %e LogL0: %e\n",logL,logL0);
    2088             :   //
    2089             :   return logL;
    2090           0 : }
    2091             : 
    2092             : //___________________________________________________________________________
    2093             : void AliTPCDcalibRes::TruncNormMod(double a, double b, double mu0, double sig0, double &muCf, double &sigCf)
    2094             : {
    2095             :   // calculate truncated mean and sigma of normal distribution as 
    2096             :   // mu_tr  = mu0 + sig0*muCf
    2097             :   // sig_tr = sig0 * sigCf
    2098             :   //
    2099           0 :   const double sqrt2PiI = 1./TMath::Sqrt(TMath::Pi()*2.);
    2100           0 :   double sigI = 1./(sig0*TMath::Sqrt(2.));
    2101           0 :   double ra = (a-mu0)*sigI, rb = (b-mu0)*sigI;
    2102           0 :   double ra2 = ra*ra, rb2 = rb*rb;
    2103           0 :   double af = ra2<100 ? sqrt2PiI*TMath::Exp(-ra2) : 0;
    2104           0 :   double bf = rb2<100 ? sqrt2PiI*TMath::Exp(-rb2) : 0;
    2105             :   //  double aF = 0.5*(1.+TMath::Erf(ra)), bF = 0.5*(1.+TMath::Erf(rb)), deltaF = bF-aF
    2106           0 :   double deltaF = 0.5*( TMath::Erf(rb) - TMath::Erf(ra) );
    2107           0 :   double deltaf = af - bf;
    2108           0 :   muCf = deltaf / deltaF;
    2109           0 :   sigCf = 1./TMath::Sqrt(1. + TMath::Sqrt(2)*(ra*af-rb*bf)/deltaF - muCf*muCf); 
    2110             :   //
    2111           0 : }
    2112             : 
    2113             : //_____________________________________________________
    2114             : Bool_t AliTPCDcalibRes::GetTruncNormMuSig(double a, double b, double &mean, double &sig)
    2115             : {
    2116             :   // get estimate of real mu and sigma of normal distribution provided
    2117             :   // the mean and rms of sample truncated between a and b
    2118             :   const double kMinWindow=1e-2,kEpsRMS = 1e-4, kEpsMu = 1e-4;
    2119             :   const int kMaxIter = 200;
    2120             :   //
    2121           0 :   if (sig<1e-12) {
    2122           0 :     AliWarningClassF("Input sigma %e is too small",sig);
    2123           0 :     return kFALSE;
    2124             :   }
    2125           0 :   if ( (b-a)/sig<kMinWindow ) {
    2126           0 :     AliWarningClassF("Truncation window %e-%e is %e sigma only",a,b,(b-a)/sig);
    2127           0 :     return kFALSE;
    2128             :   }
    2129             :   //
    2130           0 :   double sig0=sig, mean0=mean; // initial values
    2131             :   // for protection, don't allow the sigma to grow above a factor of the flat distribution
    2132           0 :   double sigMax = 1.2*(b-a)/TMath::Sqrt(12.);
    2133             :   //
    2134           0 :   double m = mean, s = sig;
    2135           0 :   for (int i=0;i<kMaxIter;i++) {
    2136           0 :     double sclRMS,sclMU;
    2137           0 :     TruncNormMod(a,b,m,s, sclMU,sclRMS);
    2138             :     //
    2139           0 :     s = sig * sclRMS;
    2140             :     double mPrev = m, sPrev = s;
    2141           0 :     m = mean - sclMU*s;
    2142             :     //printf("%d -> M: %e S: %e\n",i,m, s);
    2143           0 :     if ( s>sigMax) {
    2144             : 
    2145             :       //      printf("Iteration took sigma to twice of the flat distribution for "
    2146             :       //             "mu0=%+.3e sig0=%.3e in %+.3e:%+.3e interval\n",mean0,sig0, a,b);
    2147           0 :       if (TMath::Abs(m-mean0)>sig0) {
    2148             :         //      printf("Abandoning and returning input sigma and mean\n");
    2149             :         m = mean0; s = sig0;
    2150           0 :       }
    2151           0 :       break;
    2152             :     }
    2153           0 :     if (TMath::Abs(1.-sPrev/s)<kEpsRMS && TMath::Abs(m-mPrev)<kEpsMu ) break;
    2154           0 :   }
    2155             :   //
    2156           0 :   mean = m;
    2157           0 :   sig  = s;
    2158             : 
    2159             :   return kTRUE;
    2160           0 : }
    2161             : 
    2162             : //_________________________________________________
    2163             : void AliTPCDcalibRes::InitFieldGeom(Bool_t field,Bool_t geom)
    2164             : {
    2165             :   // init geometry and field
    2166             :   // this requires the field and the geometry ...
    2167           0 :   if (fRun<1) AliFatal("Run number is not provided");
    2168           0 :   AliCDBManager* man = AliCDBManager::Instance();
    2169           0 :   if (fOCDBPath.IsNull()) fOCDBPath = "raw://";
    2170           0 :   if (!man->IsDefaultStorageSet()) man->SetDefaultStorage(fOCDBPath);
    2171           0 :   if (man->GetRun()!=fRun) man->SetRun(fRun);
    2172             :   //
    2173           0 :   Bool_t geomOK = AliGeomManager::GetGeometry() != 0;
    2174           0 :   if (geom && !geomOK) {
    2175           0 :     AliGeomManager::LoadGeometry();
    2176           0 :     AliGeomManager::ApplyAlignObjsFromCDB("TPC");
    2177           0 :   }
    2178           0 :   AliMagF* fld = (AliMagF*)TGeoGlobalMagField::Instance()->GetField();
    2179           0 :   if (!fld && field) {
    2180           0 :     AliGRPManager grpMan;
    2181           0 :     grpMan.ReadGRPEntry();
    2182           0 :     grpMan.SetMagField();
    2183           0 :     fld = (AliMagF*)TGeoGlobalMagField::Instance()->GetField();
    2184           0 :   }
    2185           0 :   if (fld) fBz = fld->SolenoidField();
    2186           0 : }
    2187             : 
    2188             : 
    2189             : //___________________________________________________________________________
    2190             : THnF* AliTPCDcalibRes::CreateVoxelStatHisto(int sect)
    2191             : {
    2192             :   // prepare histogram to store the means of distributions within the voxel
    2193             : 
    2194             :   // create binning for voxels statistics histograms
    2195           0 :   Int_t    voxNBins[kVoxHDim];
    2196           0 :   Double_t voxBinMin[kVoxHDim],voxBinMax[kVoxHDim];
    2197           0 :   TString  voxAxisName[kVoxHDim];
    2198             : 
    2199           0 :   voxAxisName[kVoxF] = "Y2X_Bin";
    2200           0 :   voxNBins[kVoxF]    = fNY2XBins;
    2201           0 :   voxBinMin[kVoxF]   = 0;
    2202           0 :   voxBinMax[kVoxF]   = fNY2XBins;
    2203             :   //
    2204           0 :   voxAxisName[kVoxX]   = "X_Bin";
    2205           0 :   voxNBins[kVoxX]      = fNXBins;
    2206           0 :   voxBinMin[kVoxX]     = 0;
    2207           0 :   voxBinMax[kVoxX]     = fNXBins;
    2208             :   //
    2209           0 :   voxAxisName[kVoxZ]   = "Z2X_Bin";
    2210           0 :   voxNBins[kVoxZ]      = fNZ2XBins;
    2211           0 :   voxBinMin[kVoxZ]     = 0;
    2212           0 :   voxBinMax[kVoxZ]     = fNZ2XBins;
    2213             :   //
    2214           0 :   voxAxisName[kVoxV] = "Stat_Bin";
    2215           0 :   voxNBins[kVoxV]    = kVoxHDim;
    2216           0 :   voxBinMin[kVoxV]   = 0;
    2217           0 :   voxBinMax[kVoxV]   = kVoxHDim;
    2218             :   //
    2219           0 :   THnF* h = new THnF(Form("hs%d",sect),"",kVoxHDim,voxNBins,voxBinMin,voxBinMax);
    2220           0 :   for (int i=0;i<kVoxHDim;i++) h->GetAxis(i)->SetName(voxAxisName[i].Data());
    2221           0 :   h->SetEntries(1); // otherwise drawing does not work well
    2222             :   return h;
    2223           0 : }
    2224             : 
    2225             : //===============================================================
    2226             : //
    2227             : //                   TRACK VALIDATION >>>>>>>>>>>>>>>>>>>>>>>>>>>
    2228             : //
    2229             : 
    2230             : //__________________________________________________________________________________
    2231             : Bool_t AliTPCDcalibRes::ValidateTrack()
    2232             : {
    2233             :   // if (nCl<fMinNCl) return kFALSE;
    2234           0 :  if (fNCl<fNVoisinMALong) return kFALSE;
    2235             : 
    2236           0 :   Bool_t rejCl[kNPadRows];
    2237           0 :   float rmsLong = 0.f;
    2238           0 :   int nRej = CheckResiduals(rejCl, rmsLong);
    2239           0 :   if (float(nRej)/fNCl > fMaxRejFrac) return kFALSE;
    2240           0 :   if (rmsLong>fMaxRMSLong) return kFALSE;
    2241             :   //
    2242             :   // flag outliers
    2243           0 :   for (int i=fNCl;i--;) if (rejCl[i]) fArrR[i] = fArrX[i] = -1;
    2244             : 
    2245           0 :   return kTRUE;
    2246           0 : }
    2247             : 
    2248             : //______________________________________________
    2249             : void AliTPCDcalibRes::FixAlignmentBug(int sect, float q2pt, float bz, float& alp, 
    2250             :                                       float& x, float &z, float &deltaY, float &deltaZ)
    2251             : {
    2252             :   // fix alignment bug: https://alice.its.cern.ch/jira/browse/ATO-339?focusedCommentId=170850&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-170850
    2253             :   //
    2254             :   // NOTE: deltaZ in the buggy code is calculated as Ztrack_with_bug - Zcluster_w/o_bug
    2255             :   static TGeoHMatrix *mCache[72] = {0};
    2256           0 :   if (sect<0||sect>=72) {
    2257           0 :     AliErrorF("Invalid sector %d",sect);
    2258           0 :     return;
    2259             :   }
    2260           0 :   int lr = sect/36 ? (AliGeomManager::kTPC2) : (AliGeomManager::kTPC1);
    2261           0 :   TGeoHMatrix* mgt = mCache[sect];
    2262           0 :   if (!mgt) {
    2263           0 :     int volID = AliGeomManager::LayerToVolUIDSafe(lr,sect%36);
    2264           0 :     mgt = new TGeoHMatrix(*AliGeomManager::GetTracking2LocalMatrix(volID));
    2265           0 :     mgt->MultiplyLeft(AliGeomManager::GetMatrix(volID));
    2266           0 :     mCache[sect] = mgt;
    2267           0 :     AliInfoF("Caching matrix for sector %d",sect);
    2268           0 :   }  
    2269           0 :   double alpSect = ((sect%18)+0.5)*20.*TMath::DegToRad();
    2270             : 
    2271             :   // cluster in its proper alpha frame with alignment bug
    2272           0 :   double xyzClUse[3] = {x,0,z}; // this is what we read from the residual tree
    2273           0 :   double xyzTrUse[3] = {x, deltaY, z}; // track in bad cluster frame
    2274             :   //
    2275             :   // recover cluster Z position by adding deltaZ
    2276           0 :   double zClSave = xyzClUse[2] -= deltaZ;  // here the cluster is not affected by Z alignment component of the bug!
    2277           0 :   static AliExternalTrackParam trDummy;
    2278           0 :   trDummy.Local2GlobalPosition(xyzClUse,alp); // misaligned cluster in global frame
    2279           0 :   double xyz0[3]={xyzClUse[0],xyzClUse[1],xyzClUse[2]};
    2280           0 :   mgt->MasterToLocal(xyz0,xyzClUse);
    2281             :   // we got ideal cluster in the sector tracking frame, but now the Z is wrong, since it was not affected by the bug!!!
    2282             :   //
    2283           0 :   xyzClUse[2] = zClSave;
    2284             : 
    2285             :   // go to ideal cluster frame
    2286           0 :   trDummy.Local2GlobalPosition(xyzClUse,alpSect); // ideal global
    2287           0 :   double alpFix = TMath::ATan2(xyzClUse[1],xyzClUse[0]);    // fixed cluster phi
    2288           0 :   trDummy.Global2LocalPosition(xyzClUse,alpFix);     // fixed cluster in in its frame
    2289             :   //
    2290           0 :   trDummy.Local2GlobalPosition(xyzTrUse,alp); // track in global frame
    2291           0 :   trDummy.Global2LocalPosition(xyzTrUse,alpFix); // track in cluster frame
    2292           0 :   alp = alpFix;
    2293             :   //
    2294           0 :   double dx = xyzTrUse[0] - xyzClUse[0]; // x might not be the same after alignment fix
    2295             :   // deduce track slopes assuming it comes from the vertex
    2296           0 :   double tgphi = tgpXY(xyzClUse[0],xyzTrUse[1]/xyzClUse[0],q2pt,bz);
    2297           0 :   xyzTrUse[1] -= dx*tgphi;
    2298           0 :   xyzTrUse[2] -= dx*xyzClUse[2]/xyzClUse[0]; // z2x
    2299             :   //
    2300           0 :   x = xyzClUse[0];
    2301           0 :   z = xyzTrUse[2]; // we still use track Z as a reference ...
    2302           0 :   deltaY = xyzTrUse[1]-xyzClUse[1];
    2303           0 :   deltaZ = xyzTrUse[2]-xyzClUse[2];
    2304             :   //
    2305           0 : }
    2306             : 
    2307             : 
    2308             : //_______________________________________________________________
    2309             : int AliTPCDcalibRes::CheckResiduals(Bool_t* mask, float &rmsLongMA)
    2310             : {
    2311             : 
    2312             :   int ip0=0,ip1;
    2313           0 :   int sec0 = fArrSectID[ip0];
    2314           0 :   int npLast = fNCl-1;
    2315             :   //
    2316             :   const int nMinAcc = 30;
    2317           0 :   float yDiffLL[kNPadRows] = {0.f};
    2318           0 :   float zDiffLL[kNPadRows] = {0.f};
    2319           0 :   float absDevY[kNPadRows] = {0.f};
    2320           0 :   float absDevZ[kNPadRows] = {0.f};
    2321             :   
    2322           0 :   rmsLongMA = 0.f;
    2323             : 
    2324           0 :   memset(mask,0,fNCl*sizeof(Bool_t));
    2325           0 :   for (int i=0;i<fNCl;i++) {
    2326           0 :     if (fArrSectID[i]==sec0 && i<npLast) continue;
    2327             :     //
    2328             :     // sector change or end of input reached
    2329             :     // run estimators for the points in the same sector
    2330           0 :     int npSec = i-ip0;
    2331           0 :     if (i==npLast) npSec++;
    2332             :     //
    2333           0 :     DiffToLocLine(npSec, fArrX+ip0, fArrDY+ip0, fNVoisinMA, yDiffLL+ip0);
    2334           0 :     DiffToLocLine(npSec, fArrX+ip0, fArrDZ+ip0, fNVoisinMA, zDiffLL+ip0);
    2335             :     //    DiffToMA(npSec, fArrX+ip0, fArrDY+ip0, fNVoisinMA, yDiffLL+ip0);
    2336             :     //    DiffToMA(npSec, fArrX+ip0, fArrDZ+ip0, fNVoisinMA, zDiffLL+ip0);
    2337             :     //
    2338             :     ip0 = i;
    2339           0 :     sec0 = fArrSectID[ip0];
    2340           0 :   }
    2341             :   // store abs deviations
    2342             :   int naccY=0,naccZ=0;
    2343           0 :   for (int i=fNCl;i--;) {
    2344           0 :     if (yDiffLL[i]) absDevY[naccY++] = TMath::Abs(yDiffLL[i]);
    2345           0 :     if (zDiffLL[i]) absDevZ[naccZ++] = TMath::Abs(zDiffLL[i]);
    2346             :   }
    2347             :   //
    2348             :   // estimate rms on 90% smallest deviations
    2349           0 :   int kmnY = 0.9*naccY,kmnZ = 0.9*naccZ;
    2350           0 :   if (naccY<nMinAcc || naccZ<nMinAcc) { // mask all
    2351           0 :     for (int i=fNCl;i--;) mask[i] = kTRUE;
    2352           0 :     return fNCl;
    2353             :   }
    2354             : 
    2355           0 :   SelKthMin(kmnY, naccY, absDevY);
    2356           0 :   SelKthMin(kmnZ, naccZ, absDevZ);
    2357             :   float rmsKY=0,rmsKZ=0;
    2358           0 :   for (int i=kmnY;i--;) rmsKY += absDevY[i]*absDevY[i];
    2359           0 :   for (int i=kmnZ;i--;) rmsKZ += absDevZ[i]*absDevZ[i];
    2360           0 :   rmsKY = TMath::Sqrt(rmsKY/kmnY);
    2361           0 :   rmsKZ = TMath::Sqrt(rmsKZ/kmnZ);
    2362             :   //
    2363           0 :   if (rmsKY<1e-6 || rmsKZ<1e-6) {
    2364           0 :     AliWarningF("Too small RMS: %f %f",rmsKY,rmsKZ);
    2365           0 :     for (int i=fNCl;i--;) mask[i] = kTRUE;
    2366           0 :     return fNCl;
    2367             :   }
    2368             :   //
    2369             :   //  printf("RMSY %d min of %d: %f | RMSZ %d min of %d: %f\n",kmnY,naccY,rmsKY, kmnZ,naccZ,rmsKZ);
    2370             :   //
    2371             :   //
    2372           0 :   float rmsKYI = 1./rmsKY;
    2373           0 :   float rmsKZI = 1./rmsKZ;
    2374             :   int nMask=0, nacc = 0;
    2375           0 :   float yacc[kNPadRows],yDiffLong[kNPadRows];
    2376           0 :   for (int ip=0;ip<fNCl;ip++) {
    2377             : 
    2378           0 :     yDiffLL[ip] *= rmsKYI;
    2379           0 :     zDiffLL[ip] *= rmsKZI;
    2380           0 :     float dy = yDiffLL[ip], dz = zDiffLL[ip];
    2381           0 :     if (dy*dy+dz*dz>fMaxStdDevMA) {
    2382           0 :       mask[ip] = kTRUE;
    2383           0 :       nMask++;
    2384           0 :     }
    2385           0 :     else yacc[nacc++] = fArrDY[ip];
    2386             :   }
    2387             :   // rms to long-range moving average wrt surviving clusters
    2388           0 :   if (nacc>fNVoisinMALong) {
    2389           0 :     DiffToMA(nacc, yacc, fNVoisinMALong, yDiffLong);
    2390             :     float av=0,rms=0;
    2391           0 :     for (int i=0;i<nacc;i++) {
    2392           0 :       av += yDiffLong[i];
    2393           0 :       rms  += yDiffLong[i]*yDiffLong[i];
    2394             :     }
    2395           0 :     av /= nacc;
    2396           0 :     rmsLongMA = rms/nacc - av*av;
    2397           0 :     rmsLongMA = rmsLongMA>0 ? TMath::Sqrt(rmsLongMA) : 0.f;
    2398           0 :   }
    2399             :   return nMask;
    2400             :   //
    2401           0 : }
    2402             : 
    2403             : //____________________________________________________________________
    2404             : void AliTPCDcalibRes::FitCircle(int np, const float* x, const float* y, 
    2405             :                                 double &xc, double &yc, double &r, float* dy)
    2406             : {
    2407             :   // fit points to circle, if dy!=0, fill residuals
    2408             :   double x0=0.,y0=0.;
    2409           0 :   for (int i=np;i--;) {
    2410           0 :     x0 += x[i];
    2411           0 :     y0 += y[i];
    2412             :   } 
    2413           0 :   x0 /= np;
    2414           0 :   y0 /= np;
    2415             :   double su2=0,sv2=0,suv=0,su3=0,sv3=0,su2v=0,suv2=0;
    2416           0 :   for (int i=np;i--;) {
    2417           0 :     double ui = x[i]-x0, ui2 = ui*ui;
    2418           0 :     double vi = y[i]-y0, vi2 = vi*vi;
    2419           0 :     suv += ui*vi;
    2420           0 :     su2 += ui2;
    2421           0 :     sv2 += vi2;
    2422           0 :     su3 += ui2*ui;
    2423           0 :     sv3 += vi2*vi;
    2424           0 :     su2v += ui2*vi;
    2425           0 :     suv2 += ui*vi2;
    2426             :   } 
    2427           0 :   double rhsU = 0.5*(su3+suv2), rhsV = 0.5*(sv3+su2v);
    2428           0 :   double det = su2*sv2-suv*suv;
    2429           0 :   double uc  = (rhsU*sv2 - rhsV*suv)/det;
    2430           0 :   double vc  = (su2*rhsV - suv*rhsU)/det;
    2431           0 :   double r2  = uc*uc + vc*vc + (su2+sv2)/np;
    2432           0 :   xc = uc + x0;
    2433           0 :   yc = vc + y0;
    2434             :   //
    2435           0 :   if (dy) {
    2436           0 :     for (int i=np;i--;) {
    2437           0 :       double dx = x[i]-xc;
    2438           0 :       double dxr = r2 - dx*dx;
    2439           0 :       double ys = dxr>0 ? TMath::Sqrt(dxr) : 0;
    2440           0 :       double dy0 = y[i]-yc;
    2441           0 :       double dysp = dy0-ys;
    2442           0 :       double dysm = dy0+ys;
    2443           0 :       dy[i] = TMath::Abs(dysp)<TMath::Abs(dysm) ? dysp : dysm;
    2444             :     }
    2445           0 :   }
    2446           0 :   r = TMath::Sqrt(r2);
    2447           0 : }
    2448             : 
    2449             : //_________________________________________
    2450             : void AliTPCDcalibRes::DiffToMA(int np, const float *y, const int winLR, float* diffMA)
    2451             : {
    2452             :   // difference to moving average, excluding central element
    2453             :   //
    2454           0 :   double arrSumO[kNPadRows+1], *arrSum=arrSumO+1;
    2455           0 :   arrSum[-1] = 0.;
    2456           0 :   for (int ip=0;ip<np;ip++) arrSum[ip] = arrSum[ip-1]+y[ip];
    2457           0 :   for (int ip=0;ip<np;ip++) {
    2458           0 :     diffMA[ip] = 0;
    2459           0 :     int ipmn = ip-winLR;
    2460           0 :     int ipmx = ip+winLR;
    2461           0 :     if (ipmn<0)   ipmn=0;
    2462           0 :     if (ipmx>=np) ipmx=np-1;
    2463           0 :     int nrm = (ipmx-ipmn);
    2464           0 :     if (nrm<winLR) continue;
    2465           0 :     double ma = (arrSum[ipmx]-arrSum[ipmn-1] - (arrSum[ip]-arrSum[ip-1]))/nrm;
    2466           0 :     diffMA[ip] = y[ip] - ma;
    2467           0 :   }
    2468             : 
    2469           0 : }
    2470             : 
    2471             : 
    2472             : //_______________________________________________
    2473             : int AliTPCDcalibRes::DiffToLocLine(int np, const float* x, const float *y, const int nVoisin, float *diffY)
    2474             : {
    2475             :   // calculate the difference between the point and linear extrapolation from neigbourhood
    2476             :   const float kEps = 1e-9;
    2477           0 :   double sumX1b[kNPadRows+1],sumX2b[kNPadRows+1],sumYb[kNPadRows+1],sumYXb[kNPadRows+1];
    2478           0 :   double *sumX1 = sumX1b+1, *sumX2 = sumX2b+1, *sumY0 = sumYb+1, *sumYX = sumYXb+1;
    2479             :   //
    2480           0 :   sumX1[-1]=0.f;
    2481           0 :   sumX2[-1]=0.f;
    2482           0 :   sumY0[-1]=0.f;
    2483           0 :   sumYX[-1]=0.f;
    2484             :   // accumulate matrix elements for whole array, element -1 is at 0
    2485             :   double sX1=0., sX2=0., sY0=0., sYX=0.;
    2486             : 
    2487           0 :   for (int ip=0;ip<np;ip++) {
    2488           0 :     sumX1[ip] = sX1 += x[ip];
    2489           0 :     sumX2[ip] = sX2 += x[ip]*x[ip];
    2490           0 :     sumY0[ip] = sY0 += y[ip];
    2491           0 :     sumYX[ip] = sYX += y[ip]*x[ip];
    2492           0 :     diffY[ip]  = 0.0f;
    2493             :   }
    2494             :   // 
    2495             :   int nAcc = 0;
    2496           0 :   for (int ip=0;ip<np;ip++) {
    2497           0 :     float &yEst = diffY[ip];
    2498             :     // estimate from the left
    2499           0 :     int ip0 = ip-nVoisin;
    2500           0 :     int ip1 = ip+nVoisin;
    2501           0 :     if (ip0<0)   ip0=0;
    2502           0 :     if (ip1>=np) ip1=np-1;
    2503           0 :     int nrm = (ip1-ip0);
    2504           0 :     if (nrm<nVoisin) continue;
    2505           0 :     int ip0m = ip0-1, ipm = ip-1;
    2506             :     // extract sum from ip0 to ip1 from cumulant, S00=nrm, excluding tested point
    2507           0 :     sX1 = sumX1[ip1] - sumX1[ip0m] - (sumX1[ip]-sumX1[ipm]); // S01
    2508           0 :     sX2 = sumX2[ip1] - sumX2[ip0m] - (sumX2[ip]-sumX2[ipm]); // S11
    2509           0 :     sY0 = sumY0[ip1] - sumY0[ip0m] - (sumY0[ip]-sumY0[ipm]); // RHS0
    2510           0 :     sYX = sumYX[ip1] - sumYX[ip0m] - (sumYX[ip]-sumYX[ipm]); // RHS1
    2511           0 :     double det = nrm*sX2 - sX1*sX1;
    2512           0 :     if (det<kEps) continue;
    2513           0 :     double detI = 1./det;
    2514             :     // yLEst = offs + slop*x[ip] 
    2515             :     // with offs=(sY0*sX2-sYX*sX1)/det and slop=(nVoisin*sYX-sY0*sX1)/det
    2516             :     // inverse err^2 = 1/(errOffs+x^2*errSlop+2*x*errSlpOffs) with
    2517             :     // errOffs = S11/det, errSlp=S00/det, errSlpOffs=-S01/det
    2518           0 :     yEst = y[ip]-((sY0*sX2-sYX*sX1) + (nrm*sYX-sY0*sX1)*x[ip])*detI;
    2519           0 :     nAcc++;
    2520             :     //    
    2521           0 :   }
    2522           0 :   return nAcc;
    2523             :   //
    2524           0 : }
    2525             : 
    2526             : //====================================================================
    2527             : int AliTPCDcalibRes::DiffToMedLine(int np, const float* x, const float *y, const int nVoisin, float *diffY)
    2528             : {
    2529             :   int nAcc = 0;
    2530           0 :   float offs=0,slp=0;
    2531             :   float buff[kNPadRows];
    2532           0 :   for (int ip=0;ip<np;ip++) {
    2533           0 :     float &yEst = diffY[ip];
    2534           0 :     yEst = 0;
    2535             :     // estimate from the left
    2536           0 :     int ip0 = ip-nVoisin;
    2537           0 :     int ip1 = ip+nVoisin;
    2538           0 :     if (ip0<0)   ip0=0;
    2539           0 :     if (ip1>=np) ip1=np-1;
    2540           0 :     int nrm = (ip1-ip0+1);
    2541           0 :     if (nrm<nVoisin) continue;
    2542             :     int ip0m = ip0-1, ipm = ip-1;
    2543           0 :     const float *arrx = x+ip0, *arry = y+ip0;
    2544           0 :     medFit(nrm, arrx, arry, offs,slp);
    2545             :     /*
    2546             :     float asum = 0;
    2547             :     for (int i=nrm;i--;) {
    2548             :       buff[i] = arry[i] - (offs + slp*arrx[i]);
    2549             :       if (i+ip0!=ip) asum += TMath::Abs(buff[i]);
    2550             :     }
    2551             :     asum /= nrm-1;
    2552             :     yEst = buff[ip-ip0]/asum;
    2553             :     */
    2554           0 :     yEst = y[ip] - (offs + slp*x[ip]);
    2555           0 :     nAcc++;
    2556           0 :   }
    2557           0 :   return nAcc;
    2558           0 : }
    2559             : 
    2560             : //_________________________________________________________
    2561             : Int_t* AliTPCDcalibRes::LTMUnbinnedSig(int np, const float *arr, TVectorF &params , Float_t sigTgt, Float_t minFrac, Bool_t sorted)
    2562             : {
    2563             :   //
    2564             :   // LTM : Trimmed keeping at most minFrac of unbinned array to reach targer sigma
    2565             :   // 
    2566             :   // Robust statistic to estimate properties of the distribution
    2567             :   // To handle binning error special treatment
    2568             :   // for definition of unbinned data see:
    2569             :   //     http://en.wikipedia.org/w/index.php?title=Trimmed_estimator&oldid=582847999
    2570             :   //
    2571             :   // Function parameters:
    2572             :   //     np      - number of points in the array
    2573             :   //     arr     - data array (unsorted)
    2574             :   //     params  - vector with parameters
    2575             :   //             - 0 - area
    2576             :   //             - 1 - mean
    2577             :   //             - 2 - rms 
    2578             :   //             - 3 - error estimate of mean
    2579             :   //             - 4 - error estimate of RMS
    2580             :   //             - 5 - first accepted element (of sorted array)
    2581             :   //             - 6 - last accepted  element (of sorted array)
    2582             :   //
    2583             :   // On success returns index of sorted events 
    2584             :   //
    2585             :   static int *index = 0, book = 0;
    2586             :   static double* w = 0;
    2587           0 :   params[0] = 0.0f;
    2588           0 :   if (book<np) {
    2589           0 :     delete[] index;
    2590           0 :     book = np;
    2591           0 :     index = new int[book];
    2592           0 :     delete[] w;
    2593           0 :     w = new double[book+book];
    2594           0 :   }
    2595             :   //
    2596           0 :   double *wx1 = w, *wx2 = wx1+np;
    2597           0 :   if (!sorted) TMath::Sort(np,arr,index,kFALSE); // sort in increasing order
    2598           0 :   else for (int i=0;i<np;i++) index[i]=i;
    2599             :   // build cumulants
    2600             :   double sum1=0.0,sum2=0.0;
    2601           0 :   for (int i=0;i<np;i++) {
    2602           0 :     double x = arr[index[i]];
    2603           0 :     wx1[i] = (sum1+=x);
    2604           0 :     wx2[i] = (sum2+=x*x);
    2605             :   }
    2606             :   //
    2607             :   int keepMax = np;
    2608           0 :   int keepMin = minFrac*np;
    2609           0 :   if (keepMin>keepMax) keepMin = keepMax;
    2610             :   //
    2611           0 :   float sig2Tgt = sigTgt*sigTgt;
    2612           0 :   while (1) {
    2613           0 :     double minRMS = sum2+1e6;
    2614           0 :     int keepN = (keepMax+keepMin)>>1;
    2615           0 :     if (keepN<2) return 0;
    2616             :     //
    2617           0 :     params[0] = keepN;
    2618           0 :     int limI = np - keepN+1;
    2619           0 :     for (int i=0;i<limI;i++) {
    2620           0 :       int limJ = i+keepN-1;
    2621           0 :       Double_t sum1 = wx1[limJ] - (i ? wx1[i-1] : 0.0);
    2622           0 :       Double_t sum2 = wx2[limJ] - (i ? wx2[i-1] : 0.0);
    2623           0 :       double mean = sum1/keepN;
    2624           0 :       double rms2 = sum2/keepN - mean*mean;
    2625           0 :       if (rms2>minRMS) continue;
    2626             :       minRMS = rms2;
    2627           0 :       params[1] = mean;
    2628           0 :       params[2] = rms2;
    2629           0 :       params[5] = i;
    2630           0 :       params[6] = limJ;
    2631           0 :     }
    2632           0 :     if (minRMS<sig2Tgt) keepMin = keepN;
    2633             :     else                keepMax = keepN;
    2634           0 :     if (keepMin>=keepMax-1) break;
    2635           0 :   }
    2636             :   //
    2637           0 :   if (!params[0]) return 0;
    2638           0 :   params[2] = TMath::Sqrt(params[2]);
    2639           0 :   params[3] = params[2]/TMath::Sqrt(params[0]); // error on mean
    2640           0 :   params[4] = params[3]/TMath::Sqrt(2.0); // error on RMS
    2641           0 :   return index;
    2642           0 : }
    2643             : 
    2644             : //___________________________________________________________________
    2645             : float AliTPCDcalibRes::MAD2Sigma(int np, float* y)
    2646             : {
    2647             :   // Sigma calculated from median absolute deviations, https://en.wikipedia.org/wiki/Median_absolute_deviation
    2648             :   // the input array is not modified
    2649           0 :   if (np<2) return 0;
    2650           0 :   int nph = np>>1;
    2651           0 :   if (nph&0x1) nph -= 1;
    2652             :   // don't abuse stack
    2653           0 :   float *ycHeap=0, ycStack[np<kMaxOnStack ? np:1],*yc=np<kMaxOnStack ? &ycStack[0] : (ycHeap = new float[np]);
    2654           0 :   memcpy(yc,y,np*sizeof(float));
    2655           0 :   float median = (np&0x1) ? SelKthMin(nph,np,yc) : 0.5f*(SelKthMin(nph-1,np,yc)+SelKthMin(nph,np,yc));
    2656             :   // build abs differences to median
    2657           0 :   for (int i=np;i--;) yc[i] = TMath::Abs(yc[i]-median);
    2658             :   // now get median of abs deviations
    2659           0 :   median = (np&0x1) ? SelKthMin(nph,np,yc) : 0.5f*(SelKthMin(nph-1,np,yc)+SelKthMin(nph,np,yc));
    2660           0 :   delete[] ycHeap; // if any...
    2661           0 :   return median*1.4826; // convert to Gaussian sigma
    2662           0 : }
    2663             : 
    2664             : //___________________________________________________________________
    2665             : void AliTPCDcalibRes::medFit(int np, const float* x, const float* y, float &a, float &b, float* err,float delI)
    2666             : {
    2667             :   // Median linear fit: minimizes abs residuals instead of squared ones
    2668             :   // Adapted from "Numerical Recipes in C"
    2669           0 :   float aa,bb,b1,b2,f,f1,f2,sigb,chisq=0.0f;
    2670           0 :   if (np<2) {
    2671           0 :     a = b = 0.0;
    2672           0 :     if (err) {
    2673           0 :       err[0] = err[1] = err[2] = 999.;
    2674           0 :     }
    2675           0 :     return;
    2676             :   }
    2677           0 :   if (!delI) {
    2678             :     float sx=0.0f,sxx=0.0f,sy=0.0f,sxy=0.0f,del;
    2679             :     //
    2680           0 :     for (int j=np;j--;) { sx += x[j]; sxx += x[j]*x[j];}
    2681           0 :     del = np*sxx-sx*sx;
    2682             :     //
    2683           0 :     for (int j=np;j--;) { sy += y[j]; sxy += x[j]*y[j];}
    2684             :     //
    2685           0 :     delI = 1./del;
    2686           0 :     aa = (sxx*sy-sx*sxy)*delI;
    2687           0 :     bb = (np*sxy-sx*sy)*delI;
    2688           0 :     if (err) {
    2689           0 :       err[0] = sxx*delI;
    2690           0 :       err[1] = sx*delI;
    2691           0 :       err[2] = np*delI;
    2692           0 :     }
    2693           0 :   }
    2694             :   else { // initial values provided
    2695           0 :     aa = a;
    2696           0 :     bb = b;
    2697             :   }
    2698             :   //
    2699           0 :   for (int j=np;j--;) {
    2700           0 :     float temp = y[j]-(aa+bb*x[j]);
    2701           0 :     chisq += temp*temp;
    2702             :   }
    2703             :   //
    2704           0 :   sigb = TMath::Sqrt(chisq*delI);
    2705             :   b1=bb;
    2706           0 :   f1 = RoFunc(np,x,y,b1,aa);
    2707           0 :   if (sigb>0) {
    2708           0 :     b2 = bb+TMath::Sign(float(3.0f*sigb),f1);
    2709           0 :     f2 = RoFunc(np,x,y,b2,aa);
    2710           0 :     if (f1==f2) {
    2711           0 :       a = aa;
    2712           0 :       b = bb;
    2713           0 :       return;
    2714             :     }
    2715           0 :     while (f1*f2 > 0.0f) { // bracketing
    2716           0 :       bb = b2 + 1.6f*(b2-b1);
    2717             :       b1 = b2;
    2718             :       f1 = f2;
    2719             :       b2 = bb;
    2720           0 :       f2 = RoFunc(np,x,y,b2,aa);
    2721             :     }
    2722           0 :     sigb = 0.01*sigb;
    2723           0 :     while (fabs(b2-b1)>sigb) {
    2724           0 :       bb = b1 + 0.5f*(b2-b1);
    2725           0 :       if (bb==b1 || bb==b2) break;
    2726           0 :       f = RoFunc(np,x,y,bb,aa);
    2727           0 :       if (f*f1 >= 0.0f) {
    2728             :         f1=f;
    2729             :         b1=bb;
    2730           0 :       } 
    2731             :       else {
    2732             :         f2 = f;
    2733             :         b2 = bb;
    2734             :       }
    2735             :     }
    2736             :   }
    2737           0 :   a = aa;
    2738           0 :   b = bb;
    2739             :   //
    2740           0 : }
    2741             : 
    2742             : //___________________________________________________________________
    2743             : float AliTPCDcalibRes::RoFunc(int np, const float* x, const float* y, float b, float &aa)
    2744             : {
    2745             :   const float kEPS = 1.0e-7f; 
    2746             :   static float* arrTmp = 0;
    2747             :   static int nBook = 0;
    2748           0 :   if (np>nBook) { // make sure the buffer is ok
    2749           0 :     nBook = np;
    2750           0 :     delete[] arrTmp;
    2751           0 :     arrTmp = new float[nBook];
    2752           0 :   }
    2753             :   float d,sum=0.0f;
    2754           0 :   for (int j=np;j--;) arrTmp[j] = y[j]-b*x[j];
    2755             :   //
    2756           0 :   int nph = np>>1;
    2757           0 :   if (np<20) {  // it is faster to do insertion sort 
    2758           0 :     for (int i=1;i<np;i++) {
    2759           0 :       float v = arrTmp[i];
    2760             :       int j;
    2761           0 :       for (j=i;j--;) if (arrTmp[j]>v) arrTmp[j+1]=arrTmp[j]; else break;
    2762           0 :       arrTmp[j+1] = v;
    2763             :     }
    2764           0 :     aa = (np&0x1) ? arrTmp[nph] : 0.5f*(arrTmp[nph-1]+arrTmp[nph]);
    2765           0 :   }
    2766             :   else {
    2767           0 :     aa = (np&0x1) ? SelKthMin(nph,np,arrTmp) : 
    2768           0 :       0.5f*(SelKthMin(nph-1,np,arrTmp)+SelKthMin(nph,np,arrTmp));
    2769             :   }
    2770           0 :   for (int j=np;j--;) {
    2771           0 :     d = y[j] - (b*x[j] + aa);
    2772           0 :     if (y[j] != 0.0f) d /= TMath::Abs(y[j]);
    2773           0 :     if (TMath::Abs(d) > kEPS) sum += (d >= 0.0f ? x[j] : -x[j]);
    2774             :   }
    2775           0 :   return sum;
    2776             : }
    2777             : 
    2778             : //___________________________________________________________________
    2779             : Float_t AliTPCDcalibRes::SelKthMin(int k, int np, float* arr)
    2780             : {
    2781             :   // Returns the k th smallest value in the array. The input array will be rearranged
    2782             :   // to have this value in location arr[k] , with all smaller elements moved before it
    2783             :   // (in arbitrary order) and all larger elements after (also in arbitrary order).
    2784             :   // From Numerical Recipes in C++
    2785             : 
    2786             :   int i,ir,j,l,mid;
    2787             :   float a;
    2788           0 :   l=0;ir=np-1;
    2789           0 :   for (;;) {
    2790           0 :     if (ir<=l+1) {
    2791           0 :       if (ir==l+1 && arr[ir]<arr[l]) swap(arr[l],arr[ir]);
    2792           0 :       return arr[k];
    2793             :     } 
    2794             :     else {
    2795           0 :       int mid = (l+ir)>>1, i=l+1;
    2796           0 :       swap(arr[mid],arr[i]);
    2797           0 :       if (arr[i]>arr[ir]) swap(arr[i],arr[ir]);
    2798           0 :       if (arr[l]>arr[ir]) swap(arr[l]  ,arr[ir]);
    2799           0 :       if (arr[i]>arr[l])  swap(arr[i],arr[l]);
    2800             :       j=ir;
    2801           0 :       a=arr[l];
    2802           0 :       for (;;) {
    2803           0 :         do i++; while (arr[i]<a);
    2804           0 :         do j--; while (arr[j]>a);
    2805           0 :         if (j<i) break;
    2806           0 :         swap(arr[i],arr[j]);
    2807             :       }
    2808           0 :       arr[l]=arr[j];
    2809           0 :       arr[j]=a;
    2810           0 :       if (j>=k) ir=j-1;
    2811           0 :       if (j<=k) l=i;
    2812             :     }
    2813             :   }
    2814             : }
    2815             : 
    2816             : //===============================================================
    2817             : 
    2818             : //_________________________________________
    2819             : void AliTPCDcalibRes::MakeVDriftOCDB(TString targetOCDBstorage)
    2820             : {
    2821             :   // write OCDB object for VDrift (simplified copy/paste of AliTPCcalibAlignInterpolation::MakeVDriftOCDB)
    2822           0 :   TObjArray * driftArray = new TObjArray();
    2823             :   //
    2824           0 :   AliMagF* fld = (AliMagF*)TGeoGlobalMagField::Instance()->GetField();
    2825           0 :   if (!fld) InitFieldGeom(kTRUE,kFALSE);
    2826           0 :   Double_t atime[2]={0,0};
    2827           0 :   Double_t deltaZ[2]={0,0};
    2828           0 :   Double_t t0[2]={0,0};
    2829           0 :   Double_t vdgy[2]={0,0};
    2830             :   //
    2831           0 :   atime[0] = fVDriftGraph->GetX()[0];
    2832           0 :   atime[1] = fVDriftGraph->GetX()[fVDriftGraph->GetN()-1];
    2833             :   //
    2834           0 :   AliTPCParam* param = AliTPCcalibDB::Instance()->GetParameters(); // just to get Vdrift
    2835             :   //
    2836           0 :   for (Int_t ipoint=0; ipoint<=1; ipoint++){
    2837           0 :     deltaZ[ipoint]=-(*fVDriftParam)[1];  // unit OK  
    2838           0 :     vdgy[ipoint]=-(*fVDriftParam)[2];   // units OK
    2839           0 :     t0[ipoint]=-(*fVDriftParam)[0]/(1+(*fVDriftParam)[3]);       // t0 to be normalized to the ms
    2840           0 :     t0[ipoint]/=(param->GetDriftV()/1000000.); 
    2841             :   }
    2842           0 :   Double_t vdrifCorrRun=1./(1.+(*fVDriftParam)[3]);
    2843             :   //
    2844             :   TGraphErrors   *graphDELTAZ=0;
    2845             :   TGraphErrors   *graphT0=0;
    2846             :   TGraphErrors   *graphVDGY=0;
    2847             :   TGraphErrors   *graphDRIFTVD=0;
    2848             :   TGraphErrors   *graph=0;
    2849             :   //
    2850           0 :   TString grPrefix="ALIGN_ITSB_TPC_";
    2851             :   //
    2852           0 :   graphDELTAZ=new TGraphErrors(2, atime, deltaZ);
    2853           0 :   graphDELTAZ->SetName(grPrefix+"DELTAZ");
    2854           0 :   driftArray->AddLast(graphDELTAZ);
    2855           0 :   graphT0=new TGraphErrors(2, atime, t0);
    2856           0 :   graphT0->SetName(grPrefix+"T0");
    2857           0 :   driftArray->AddLast(graphT0);
    2858           0 :   graphVDGY=new TGraphErrors(2, atime, vdgy);
    2859           0 :   graphVDGY->SetName(grPrefix+"VDGY");
    2860           0 :   driftArray->AddLast(graphVDGY);
    2861             :   //
    2862             :   // drift velocity
    2863           0 :   graph = new TGraphErrors(*fVDriftGraph);
    2864           0 :   graph->SetName(grPrefix+"DRIFTVD");
    2865           0 :   Int_t npoints = graph->GetN();
    2866           0 :   for (Int_t ipoint=0; ipoint<npoints; ipoint++) {
    2867           0 :     graph->GetY()[ipoint]  = (vdrifCorrRun*(1-graph->GetY()[ipoint]))-1.;
    2868           0 :     graph->GetEY()[ipoint] = vdrifCorrRun*graph->GetEY()[ipoint];
    2869             :   }
    2870           0 :   driftArray->AddLast(graph);
    2871             :   //
    2872             :   AliCDBStorage* targetStorage = 0x0;
    2873           0 :   if (targetOCDBstorage.Length()==0) {
    2874           0 :     targetOCDBstorage+="local://"+gSystem->GetFromPipe("pwd")+"/OCDB";
    2875           0 :     targetStorage = AliCDBManager::Instance()->GetStorage(targetOCDBstorage.Data());
    2876           0 :   }
    2877           0 :   else if (targetOCDBstorage.CompareTo("same",TString::kIgnoreCase) == 0 ){
    2878           0 :     targetStorage = AliCDBManager::Instance()->GetDefaultStorage();
    2879           0 :   }
    2880             :   else {
    2881           0 :     targetStorage = AliCDBManager::Instance()->GetStorage(targetOCDBstorage.Data());
    2882             :   }
    2883             : 
    2884           0 :   AliCDBMetaData* metaData = new AliCDBMetaData;
    2885           0 :   metaData->SetObjectClassName("TObjArray");
    2886           0 :   metaData->SetResponsible("Marian Ivanov");
    2887           0 :   metaData->SetBeamPeriod(1);
    2888           0 :   metaData->SetAliRootVersion(">v5-07-20"); //AliRoot version
    2889           0 :   metaData->SetComment("AliTPCcalibAlignInterpolation Calibration of the time dependence of the drift velocity using Residual trees");
    2890           0 :   AliCDBId id1("TPC/Calib/TimeDrift", fRun, fRun);
    2891             :   
    2892             :   //now the entry owns the metadata, but NOT the data
    2893           0 :   AliCDBEntry *driftCDBentry=new AliCDBEntry(driftArray,id1,metaData,kFALSE);
    2894           0 :   targetStorage->Put(driftCDBentry); 
    2895             :   //
    2896           0 :   delete driftCDBentry;
    2897           0 : }
    2898             : 
    2899             : //_________________________________________
    2900             : void AliTPCDcalibRes::LoadVDrift()
    2901             : {
    2902             :   // load vdrift params
    2903           0 :   fVDriftGraph = 0;
    2904           0 :   fVDriftParam = 0;
    2905           0 :   TString vdname = Form("%s.root",kDriftFileName);
    2906             :   TFile *fdrift = 0;
    2907           0 :   if (gSystem->AccessPathName(vdname.Data()) || !(fdrift=TFile::Open(vdname.Data())) ) {
    2908           0 :     AliWarningF("vdrift file %s not accessible",vdname.Data());
    2909           0 :     return;
    2910             :   }
    2911           0 :   TTree * tree = (TTree*)fdrift->Get("fitTimeStat");
    2912           0 :   if (!tree) AliWarningF("tree fitTimeStat not avaliable in file %s.root",kDriftFileName);
    2913             :   else {      
    2914           0 :     tree->SetBranchAddress("grTRDReg.",&fVDriftGraph);
    2915           0 :     tree->SetBranchAddress("paramRobust.",&fVDriftParam);
    2916           0 :     tree->GetEntry(0);
    2917           0 :     if (fVDriftGraph==NULL || fVDriftGraph->GetN()<=0) {
    2918           0 :       AliWarning("ITS/TRD drift calibration not availalble. Trying ITS/TOF");
    2919           0 :       tree->SetBranchAddress("grTOFReg.",&fVDriftGraph);
    2920           0 :       tree->GetEntry(0);
    2921             :     }
    2922             :   }
    2923           0 :   delete tree;
    2924           0 :   delete fdrift;
    2925           0 : }
    2926             : 
    2927             : //_________________________________________
    2928             : float AliTPCDcalibRes::GetDriftCorrection(float z, float x, float phi, int rocID)
    2929             : {
    2930             :   // apply vdrift correction
    2931           0 :   if (!fVDriftParam) return 0.f;
    2932           0 :   int side = ((rocID/kNSect)&0x1) ? -1:1; // C:A
    2933           0 :   float drift = side>0 ? kZLim[0]-z : z+kZLim[1];
    2934           0 :   float gy    = TMath::Sin(phi)*x;
    2935             :   Double_t pvecFit[3];
    2936           0 :   pvecFit[0]= side;             // z shift (cm)
    2937           0 :   pvecFit[1]= drift*gy/kZLim[side<0];   // global y gradient
    2938           0 :   pvecFit[2]= drift;            // drift length
    2939           0 :   float expected = (fVDriftParam==NULL) ? 0:
    2940           0 :     (*fVDriftParam)[0]+
    2941           0 :     (*fVDriftParam)[1]*pvecFit[0]+
    2942           0 :     (*fVDriftParam)[2]*pvecFit[1]+
    2943           0 :     (*fVDriftParam)[3]*pvecFit[2];
    2944           0 :   return -side*(expected+fCorrTime*drift);
    2945             :   //
    2946           0 : }
    2947             : 
    2948             : //_____________________________________________________
    2949             : float AliTPCDcalibRes::tgpXY(float x, float y, float q2p, float bz)
    2950             : {
    2951             :   // get the tg of primary track inclination wrt padrow given
    2952             :   // that it was registered at X,Y sector coordinates
    2953           0 :   float c = q2p*bz*(-0.299792458e-3f);
    2954           0 :   if (TMath::Abs(c)<1e-9) return y/x;
    2955           0 :   float r2 = x*x+y*y;
    2956           0 :   float det = 4./r2 - c*c;
    2957             :   float snp  = 0;
    2958           0 :   if (det<0) {
    2959           0 :     snp = TMath::Sign(-0.8f,c);
    2960           0 :     AliWarningF("track of q2p=%f cannot reach x:%f y:%f",q2p,x,y);
    2961           0 :   }
    2962             :   else {
    2963           0 :     snp = 0.5f*(y*TMath::Sqrt(det)-c*x); // snp at vertex
    2964           0 :     snp += x*c;  // snp at x,y
    2965             :   }
    2966           0 :   return snp/TMath::Sqrt((1.f-snp)*(1.f+snp));
    2967           0 : }
    2968             : 
    2969             : 
    2970             : //=========================================================================
    2971             : //
    2972             : //   IO related methods
    2973             : //
    2974             : //=========================================================================
    2975             : //
    2976             : //___________________________________________________________________
    2977             : void AliTPCDcalibRes::WriteStatHistos()
    2978             : {
    2979             :   // write stat histos
    2980           0 :   TString statOutName = Form("%s.root",kStatOut);
    2981           0 :   TFile* statOutFile = TFile::Open(statOutName.Data(),"recreate");
    2982           0 :   for (int is=0;is<kNSect2;is++) fStatHist[is]->Write("", TObject::kOverwrite);
    2983           0 :   statOutFile->Close();
    2984           0 :   delete statOutFile;
    2985             :   //
    2986           0 : }
    2987             : 
    2988             : //___________________________________________________________________
    2989             : void AliTPCDcalibRes::LoadStatHistos()
    2990             : {
    2991             :   // load bin stat histos
    2992           0 :   if (fStatHist[0]) return; // histos are in memory
    2993           0 :   TString statOutName = Form("%s.root",kStatOut);
    2994           0 :   TFile* statOutFile = TFile::Open(statOutName.Data());
    2995           0 :   if (!statOutFile) AliFatalF("LoadStatHistos: failed to read file %s",statOutName.Data()); 
    2996           0 :   for (int is=0;is<kNSect2;is++) {
    2997           0 :     fStatHist[is] = (THnF*) statOutFile->Get(Form("hs%d",is));
    2998           0 :     if (!fStatHist[is]) AliFatalF("LoadStatHistos: failed to read secto %d histo from %s",is,statOutName.Data());
    2999           0 :     fArrNDStat[is] = (TNDArrayT<float>*)&fStatHist[is]->GetArray();
    3000             :   }
    3001           0 :   statOutFile->Close();
    3002           0 :   delete statOutFile;
    3003             :   //
    3004           0 : }
    3005             : 
    3006             : //___________________________________________________________________
    3007             : void AliTPCDcalibRes::WriteResTree()
    3008             : {
    3009             :   // output file for results tree
    3010           0 :   TStopwatch sw;
    3011           0 :   sw.Start();
    3012           0 :   bres_t voxRes, *voxResP=&voxRes;
    3013             : 
    3014           0 :   AliSysInfo::AddStamp("ResTree",0,0,0,0);
    3015           0 :   if (fChebCorr) fChebCorr->Init();
    3016           0 :   TFile* flOut = new TFile(GetVoxResFileName(),"recreate");
    3017           0 :   TTree* resTree = new TTree("voxRes","final distortions, see GetListOfAliases");
    3018           0 :   resTree->Branch("res", &voxRes);
    3019           0 :   resTree->Branch("L",&fLumiCOG);
    3020           0 :   for (int i=0;i<kVoxDim;i++) {
    3021           0 :     resTree->SetAlias(kVoxName[i],Form("bvox[%d]",i));
    3022           0 :     resTree->SetAlias(Form("%sAV",kVoxName[i]),Form("stat[%d]",i));
    3023             :   }
    3024           0 :   resTree->SetAlias(Form("%sAV",kVoxName[kVoxV]),Form("stat[%d]",kVoxV));
    3025           0 :   for (int i=0;i<kResDim;i++) {
    3026           0 :     resTree->SetAlias(kResName[i],Form("D[%d]",i));
    3027           0 :     resTree->SetAlias(Form("%sS",kResName[i]),Form("DS[%d]",i));
    3028           0 :     resTree->SetAlias(Form("%sC",kResName[i]),Form("DC[%d]",i));
    3029           0 :     resTree->SetAlias(Form("%sE",kResName[i]),Form("E[%d]",i));
    3030             :   }
    3031             :   //
    3032           0 :   resTree->SetAlias("fitOK",Form("(flags&0x%x)==0x%x",kDistDone,kDistDone));
    3033           0 :   resTree->SetAlias("dispOK",Form("(flags&0x%x)==0x%x",kDispDone,kDispDone));
    3034           0 :   resTree->SetAlias("smtOK",Form("(flags&0x%x)==0x%x",kSmoothDone,kSmoothDone));
    3035           0 :   resTree->SetAlias("masked",Form("(flags&0x%x)==0x%x",kMasked,kMasked));
    3036             :   //
    3037           0 :   for (int is=0;is<kNSect2;is++) { 
    3038             : 
    3039           0 :     bres_t* sectData = fSectGVoxRes[is];
    3040           0 :     if (!sectData) {
    3041           0 :       AliWarningF("No processed data for sector %d",is);
    3042           0 :       continue;
    3043             :     }
    3044             : 
    3045             :     // now store the data for the sector
    3046           0 :     for (int iz=0;iz<fNZ2XBins;iz++) {
    3047           0 :       for (int ix=0;ix<fNXBins;ix++) { 
    3048           0 :         for (int ip=0;ip<fNY2XBins;ip++) {
    3049           0 :           int binGlo = GetVoxGBin(ix,ip,iz);
    3050           0 :           bres_t *voxel = &sectData[binGlo];
    3051           0 :           if (fChebCorr) {
    3052           0 :             int row = GetRowID(voxel->stat[kVoxX]);
    3053             :             int roc = is;
    3054           0 :             if (row>=kNRowIROC) {roc += kNSect2; row -= kNRowIROC;}
    3055           0 :             fChebCorr->Eval(roc,row, voxel->stat[kVoxF],voxel->stat[kVoxZ],voxel->DC);
    3056           0 :           }
    3057           0 :           memcpy(&voxRes,voxel,sizeof(bres_t)); // store in the sector data array
    3058           0 :           resTree->Fill();
    3059             :         }
    3060             :       }
    3061             :     }    
    3062             :     //
    3063           0 :   } // end of sector loop
    3064             :   //
    3065             :   //
    3066             :   // write small trees with luminosity and vdrift info
    3067             :   //
    3068           0 :   TTree* infoTree = new TTree("runInfo","run information");
    3069           0 :   if (fLumiCTPGraph) infoTree->Branch("lumiCTP", &fLumiCTPGraph);
    3070           0 :   if (fVDriftGraph)  infoTree->Branch("driftGraph", &fVDriftGraph);
    3071           0 :   if (fVDriftParam)  infoTree->Branch("driftParam", &fVDriftParam);
    3072           0 :   infoTree->Branch("tminCTPrun",&fTMinCTP);
    3073           0 :   infoTree->Branch("tmaxCTPrun",&fTMaxCTP);
    3074           0 :   infoTree->Branch("tminTBin",&fTMin);
    3075           0 :   infoTree->Branch("tmaxTBin",&fTMax);
    3076           0 :   infoTree->Fill();
    3077             :   //
    3078           0 :   flOut->cd();
    3079           0 :   resTree->Write("", TObject::kOverwrite);
    3080           0 :   infoTree->Write("", TObject::kOverwrite);
    3081           0 :   delete resTree;
    3082           0 :   delete infoTree;
    3083             :   //
    3084           0 :   if (fChebCorr) {
    3085           0 :     fChebCorr->Write();
    3086             :   }
    3087             :   //
    3088           0 :   flOut->Close();
    3089           0 :   delete flOut;
    3090             :   //
    3091           0 :   sw.Stop();
    3092           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
    3093           0 :   AliSysInfo::AddStamp("ResTree",1,0,0,0);
    3094             : 
    3095           0 : }
    3096             : 
    3097             : //___________________________________________________________________
    3098             : Bool_t AliTPCDcalibRes::LoadDataFromResTree(const char* resTreeFile)
    3099             : {
    3100             :   // Fill voxels info from existing resVox tree for reprocessing
    3101           0 :   TStopwatch sw;
    3102           0 :   sw.Start();
    3103           0 :   bres_t voxRes, *voxResP=&voxRes;
    3104             :   //
    3105           0 :   TTree* resTree = LoadTree(resTreeFile);
    3106           0 :   if (!resTree) {AliErrorF("Failed to extract resTree from %s",resTreeFile); return kFALSE;}
    3107           0 :   resTree->SetBranchAddress("res", &voxResP);
    3108             :   //
    3109           0 :   int nent = resTree->GetEntries();
    3110           0 :   if (nent != kNSect2*fNGVoxPerSector) AliFatalF("resTree from %s has %d voxels per sector, this object: %d",
    3111             :                                                  resTreeFile,nent/kNSect2,fNGVoxPerSector);
    3112             :   //
    3113           0 :   for (int is=0;is<kNSect2;is++) { 
    3114           0 :     if (fSectGVoxRes[is]) delete[] fSectGVoxRes[is];
    3115           0 :     bres_t* sectData = fSectGVoxRes[is] = new bres_t[fNGVoxPerSector];
    3116             :   }
    3117           0 :   for (int ient=0;ient<nent;ient++) {
    3118             :     //
    3119           0 :     resTree->GetEntry(ient);
    3120           0 :     bres_t* sectData = fSectGVoxRes[voxRes.bsec];
    3121           0 :     int binGlo = GetVoxGBin(voxRes.bvox);
    3122           0 :     bres_t *voxel = &sectData[binGlo];
    3123           0 :     memcpy(voxel,&voxRes,sizeof(bres_t));
    3124             :     // the X distortion contribution was already subtracted from the Y,Z components, restore it
    3125           0 :     voxel->D[kResZ]  -= voxel->stat[kVoxZ]*voxel->DS[kResX];
    3126             :     // reset smoothed params
    3127           0 :     voxel->flags &= ~(kSmoothDone|kMasked);
    3128           0 :     for (int ir=kResDim;ir--;) voxel->DS[ir]=voxel->DC[ir]=0.f;
    3129             :   } // end of sector loop
    3130             :   //
    3131           0 :   CloseTreeFile(resTree);
    3132             :   //
    3133           0 :   sw.Stop();
    3134           0 :   AliInfoF("timing: real: %.3f cpu: %.3f",sw.RealTime(), sw.CpuTime());
    3135             :   //
    3136             :   return kTRUE;
    3137           0 : }
    3138             : 
    3139             : 
    3140             : //=========================================================================
    3141             : //
    3142             : //   fitting/smoothing related methods
    3143             : //
    3144             : //=========================================================================
    3145             : 
    3146             : //_____________________________________________________
    3147             : Bool_t AliTPCDcalibRes::FitPoly2(const float* x,const float* y, const float* w, int np, float *res, float *err)
    3148             : {
    3149             :   // poly2 fitter
    3150           0 :   if (np<3) return kFALSE; // no enough points
    3151             :   double sumW[5]={0},sumY[3]={0};
    3152           0 :   for (int ip=np;ip--;) {
    3153           0 :     double ww = w ? w[ip] : 1.0;
    3154           0 :     sumW[0] += ww;
    3155           0 :     sumY[0] += ww*y[ip];
    3156           0 :     sumW[1] += (ww*=x[ip]); 
    3157           0 :     sumY[1] += ww*y[ip];
    3158           0 :     sumW[2] += (ww*=x[ip]); 
    3159           0 :     sumY[2] += ww*y[ip];
    3160           0 :     sumW[3] += (ww*=x[ip]); 
    3161           0 :     sumW[4] += (ww*=x[ip]); 
    3162             :   }
    3163           0 :   double min00 = (sumW[2]*sumW[4]-sumW[3]*sumW[3]);
    3164           0 :   double min01 = (sumW[1]*sumW[4]-sumW[3]*sumW[2]);
    3165           0 :   double min02 = (sumW[1]*sumW[3]-sumW[2]*sumW[2]);
    3166           0 :   double min11 = (sumW[0]*sumW[4]-sumW[2]*sumW[2]);
    3167           0 :   double min12 = (sumW[0]*sumW[3]-sumW[2]*sumW[1]);
    3168           0 :   double min22 = (sumW[0]*sumW[2]-sumW[1]*sumW[1]);
    3169           0 :   double det  = sumW[0]*min00
    3170           0 :     -           sumW[1]*min01
    3171           0 :     +           sumW[2]*min02;
    3172           0 :   if (TMath::Abs(det)<1e-12) return kFALSE;
    3173           0 :   double detI = 1./det;
    3174           0 :   double det0 = sumY[0]*min00
    3175           0 :     -           sumW[1]*(sumY[1]*sumW[4]-sumW[3]*sumY[2]) 
    3176           0 :     +           sumW[2]*(sumY[1]*sumW[3]-sumW[2]*sumY[2]);
    3177           0 :   double det1 = sumW[0]*(sumY[1]*sumW[4]-sumW[3]*sumY[2]) 
    3178           0 :     -           sumY[0]*min01
    3179           0 :     +           sumW[2]*(sumW[1]*sumY[2]-sumY[1]*sumW[2]);
    3180           0 :   double det2 = sumW[0]*(sumW[2]*sumY[2]-sumY[1]*sumW[3]) 
    3181           0 :     -           sumW[1]*(sumW[1]*sumY[2]-sumY[1]*sumW[2]) 
    3182           0 :     +           sumY[0]*min02;
    3183           0 :   res[0] = det0*detI;
    3184           0 :   res[1] = det1*detI;
    3185           0 :   res[2] = det2*detI;
    3186             :   //
    3187           0 :   if (err) {
    3188           0 :     err[0] = min00*detI; // e00
    3189           0 :     err[1] =-min01*detI; // e10
    3190           0 :     err[2] = min11*detI; // e11
    3191           0 :     err[3] = min02*detI; // e20
    3192           0 :     err[4] =-min12*detI; // e21
    3193           0 :     err[5] = min22*detI; // e21
    3194           0 :   }
    3195             :   //
    3196             :   return kTRUE;
    3197           0 : }
    3198             : 
    3199             : //_____________________________________________________
    3200             : Bool_t AliTPCDcalibRes::FitPoly1(const float* x,const float* y, const float* w, int np, float *res, float *err)
    3201             : {
    3202             :   // poly1 fitter
    3203           0 :   if (np<2) return kFALSE; // no enough points
    3204             :   double sumW[3]={0},sumY[2]={0};
    3205           0 :   for (int ip=np;ip--;) {
    3206           0 :     double ww = w ? w[ip]:1.0;
    3207           0 :     sumW[0] += ww;
    3208           0 :     sumY[0] += ww*y[ip];
    3209           0 :     sumW[1] += (ww*=x[ip]); 
    3210           0 :     sumY[1] += ww*y[ip];
    3211           0 :     sumW[2] += (ww*=x[ip]);
    3212             :   }
    3213           0 :   double det  = sumW[0]*sumW[2] - sumW[1]*sumW[1];
    3214           0 :   if (TMath::Abs(det)<1e-12) return kFALSE;
    3215           0 :   double detI = 1./det;
    3216           0 :   double det0 = sumY[0]*sumW[2] - sumW[1]*sumY[1];
    3217           0 :   double det1 = sumW[0]*sumY[1] - sumY[0]*sumW[1];
    3218           0 :   res[0] = det0*detI;
    3219           0 :   res[1] = det1*detI;
    3220             :   //
    3221           0 :   if (err) {
    3222           0 :     err[0] = sumW[2]*detI; // e00
    3223           0 :     err[1] =-sumW[1]*detI; // e10
    3224           0 :     err[2] = sumW[0]*detI; // e11
    3225           0 :   }
    3226             :   //
    3227             :   return kTRUE;
    3228           0 : }
    3229             : 
    3230             : //________________________________
    3231             : Int_t AliTPCDcalibRes::ValidateVoxels(int isect)
    3232             : {
    3233             :   // apply voxel validation cuts, calculate number of low stat or masked voxels
    3234             :   int cntMasked=0, cntInvalid=0;
    3235             :   //
    3236           0 :   fXBinIgnore[isect].ResetAllBits();
    3237           0 :   bres_t* sectData = fSectGVoxRes[isect];
    3238           0 :   for (int ix=0;ix<fNXBins;ix++) {
    3239             :     int nvalidXBin = 0;
    3240           0 :     for (int ip=0;ip<fNY2XBins;ip++) {
    3241           0 :       for (int iz=0;iz<fNZ2XBins;iz++) {  // extract line in z
    3242           0 :         int binGlo = GetVoxGBin(ix,ip,iz);
    3243           0 :         bres_t *voxRes = &sectData[binGlo];
    3244           0 :         Bool_t voxOK = voxRes->flags&kDistDone && !(voxRes->flags&kMasked);
    3245           0 :         if (voxOK) {
    3246             :           // check fit errors
    3247           0 :           if (voxRes->E[kResY]*voxRes->E[kResY]>fMaxFitYErr2 ||
    3248           0 :               voxRes->E[kResX]*voxRes->E[kResX]>fMaxFitXErr2 ||
    3249           0 :               TMath::Abs(voxRes->EXYCorr)>fMaxFitXYCorr) voxOK = kFALSE;
    3250             :           // check raw distributions sigmas
    3251           0 :           if (voxRes->dYSigMAD > fMaxSigY || voxRes->dZSigLTM > fMaxSigZ) voxOK = kFALSE;
    3252           0 :           if (!voxOK) cntMasked++;
    3253             :         }
    3254           0 :         if (voxOK) {
    3255           0 :           nvalidXBin++;
    3256           0 :           voxRes->flags |= kDistDone;
    3257           0 :         }
    3258             :         else {
    3259           0 :           cntInvalid++;
    3260           0 :           voxRes->flags |= kMasked;
    3261             :         }
    3262             :       } // loop over Z
    3263             :     } // loop over Y
    3264             :     //
    3265           0 :     fValidFracXBin[isect][ix] = Float_t(nvalidXBin)/(fNY2XBins*fNZ2XBins);
    3266           0 :     if (fValidFracXBin[isect][ix]<fMinValidVoxFracDrift) {
    3267           0 :       AliWarningF("Sector%2d: Xbin%3d has %4.1f%% of voxels valid (%d out of %d)",
    3268             :                   isect,ix,100*fValidFracXBin[isect][ix],nvalidXBin,fNY2XBins*fNZ2XBins);
    3269           0 :     }
    3270             :     //
    3271             :   } // loop over X
    3272             :   //
    3273             :   // mask X-bins which cannot be smoothed
    3274             :   int nValidInPatch = 0;
    3275             :   // 1st loop: find bad regions
    3276           0 :   short nbadReg=0,badStart[kNPadRows],badEnd[kNPadRows];
    3277             :   Bool_t prevBad = kFALSE;
    3278             :   float fracBadRows = 0;
    3279           0 :   for (int ix=0;ix<fNXBins;ix++) {
    3280           0 :     if (fValidFracXBin[isect][ix]<fMinValidVoxFracDrift) {
    3281           0 :       fracBadRows++;
    3282           0 :       if (prevBad) badEnd[nbadReg] = ix;
    3283             :       else {
    3284           0 :         badStart[nbadReg] = badEnd[nbadReg] = ix;
    3285             :         prevBad = kTRUE; 
    3286             :       }
    3287             :     }
    3288             :     else {
    3289           0 :       if (prevBad) {
    3290             :         prevBad = kFALSE;
    3291           0 :         nbadReg++;
    3292           0 :       }
    3293             :     }
    3294             :   }
    3295           0 :   if (prevBad) nbadReg++; // last bad region was not closed
    3296             :   //
    3297           0 :   fracBadRows /= fNXBins;
    3298           0 :   if (fracBadRows>fMaxBadRowsPerSector) {
    3299           0 :     AliWarningF("Sector%2d: Fraction of bad X-bins %.3f > %.3f: masking whole sector",
    3300             :                 isect,fracBadRows,fMaxBadRowsPerSector);
    3301           0 :     for (int ix=0;ix<fNXBins;ix++) SetXBinIgnored(isect,ix);
    3302           0 :   }
    3303             :   else {
    3304             :   //
    3305             :   // 2nd loop: disable those regions which cannot be smoothed
    3306           0 :     for (int ibad=0;ibad<nbadReg;ibad++) {
    3307           0 :       short badSize=badEnd[ibad]-badStart[ibad]+1,badSizeNext=ibad<(nbadReg-1) ? badEnd[ibad]-badStart[ibad]+1 : 0;
    3308             :       // disable too large bad patches
    3309           0 :       if (badSize>fMaxBadXBinsToCover) for (int i=0;i<badSize;i++) SetXBinIgnored(isect,badStart[ibad]+i);
    3310             :       // disable too small isolated good patches
    3311           0 :       if (badSizeNext>fMaxBadXBinsToCover && (badStart[ibad+1]-badEnd[ibad]-1)<fMinGoodXBinsToCover) {
    3312           0 :         for (int i=badEnd[ibad]+1;i<badStart[ibad+1];i++) SetXBinIgnored(isect,i);
    3313           0 :       }
    3314             :     }
    3315           0 :     if (nbadReg) {
    3316             :       int ib=0;
    3317             :       // is 1st good patch too small?
    3318           0 :       if (GetXBinIgnored(isect,badStart[0]) && badStart[ib]<fMinGoodXBinsToCover) {
    3319           0 :         for (int i=0;i<badStart[ib];i++) SetXBinIgnored(isect,i);
    3320           0 :       }
    3321             :       // last good patch is too small?
    3322           0 :       ib = nbadReg-1;
    3323           0 :       if (GetXBinIgnored(isect,badStart[ib]) && (fNXBins-badEnd[ib]-1)<fMinGoodXBinsToCover) {
    3324           0 :         for (int i=badEnd[ib]+1;i<fNXBins;i++) SetXBinIgnored(isect,i);
    3325           0 :       }
    3326           0 :     }
    3327             :     //
    3328             :   }
    3329             :   //
    3330           0 :   int nMaskedRows = fXBinIgnore[isect].CountBits();
    3331           0 :   AliInfoF("Sector%2d: Voxel stat: Masked: %5d(%07.3f%%) Invalid: %5d(%07.3f%%)  -> Masked %3d rows out of %3d",isect,
    3332             :            cntMasked, 100*float(cntMasked)/fNGVoxPerSector,
    3333             :            cntInvalid,100*float(cntInvalid)/fNGVoxPerSector,
    3334             :            nMaskedRows,fNXBins);
    3335             :   //
    3336           0 :   return fNXBins-nMaskedRows;
    3337           0 : }
    3338             : 
    3339             : //________________________________
    3340             : Int_t AliTPCDcalibRes::Smooth0(int isect)
    3341             : {
    3342             :   // apply linear regression kernel smoother 
    3343             :   int cnt = 0;
    3344           0 :   bres_t* sectData = fSectGVoxRes[isect];
    3345           0 :   for (int ix=0;ix<fNXBins;ix++) {
    3346           0 :     if (GetXBinIgnored(isect,ix)) continue;
    3347           0 :     for (int ip=0;ip<fNY2XBins;ip++) {
    3348           0 :       for (int iz=0;iz<fNZ2XBins;iz++) {  // extract line in z
    3349           0 :         int binGlo = GetVoxGBin(ix,ip,iz);
    3350           0 :         bres_t *vox = &sectData[binGlo];
    3351           0 :         vox->flags &= ~kSmoothDone;
    3352           0 :         Bool_t res = GetSmoothEstimate(vox->bsec,vox->stat[kVoxX],vox->stat[kVoxF],vox->stat[kVoxZ],
    3353             :                                        BIT(kResX)|BIT(kResY)|BIT(kResZ), // at this moment we cannot smooth dispersion
    3354           0 :                                        vox->DS);
    3355           0 :         if (!res) fNSmoothingFailedBins[isect]++;
    3356           0 :         else vox->flags |= kSmoothDone;
    3357             :       }
    3358             :     }
    3359           0 :   }
    3360             :   // now subtract the dX contribution to DZ
    3361           0 :   for (int ix=0;ix<fNXBins;ix++) {
    3362           0 :     if (GetXBinIgnored(isect,ix)) continue;
    3363           0 :     for (int ip=0;ip<fNY2XBins;ip++) {
    3364           0 :       for (int iz=0;iz<fNZ2XBins;iz++) {
    3365           0 :         int binGlo = GetVoxGBin(ix,ip,iz);
    3366           0 :         bres_t *vox = &sectData[binGlo];
    3367           0 :         if (!(vox->flags&kSmoothDone)) continue;
    3368           0 :         vox->DS[kResZ] += vox->stat[kVoxZ]*vox->DS[kResX]; // remove slope*dx contribution from DZ
    3369           0 :         vox->D[kResZ]  += vox->stat[kVoxZ]*vox->DS[kResX]; // remove slope*dx contribution from DZ
    3370           0 :       }
    3371             :     }
    3372           0 :   }
    3373             :   //
    3374           0 :   return cnt;
    3375             : }
    3376             : 
    3377             : //________________________________________________________________
    3378             : Bool_t AliTPCDcalibRes::GetSmoothEstimate(int isect, float x, float p, float z, Int_t which, float *res, float *deriv)
    3379             : {
    3380             :   // get smooth estimate of distortions mentioned in "which" bit pattern for point in sector coordinates (x,y/x,z/x)
    3381             :   // smoothing results also saved in the fLastSmoothingRes (allow derivative calculation)
    3382             :   //
    3383           0 :   int minPointsDir[kVoxDim]={0}; // min number of points per direction
    3384             :   //
    3385             :   const float kTrialStep = 0.5;
    3386           0 :   Bool_t doDim[kResDim] = {kFALSE};
    3387           0 :   for (int i=0;i<kResDim;i++) {
    3388           0 :     doDim[i] = (which&(0x1<<i))>0;
    3389           0 :     if (doDim[i]) res[i] = 0;
    3390             :   }
    3391             :   //
    3392             :   // extimate smoothing matrix size and min number of points
    3393             :   int matSize = kSmtLinDim;
    3394           0 :   for (int i=0;i<kVoxDim;i++) {
    3395           0 :     minPointsDir[i] = 3; // for pol1 smoothing require at least 3 points 
    3396           0 :     if (fSmoothPol2[i]) {
    3397           0 :       minPointsDir[i]++;
    3398           0 :       matSize++;
    3399           0 :     }
    3400             :   } 
    3401           0 :   double cmat[kResDim][kMaxSmtDim*(kMaxSmtDim+1)/2];
    3402             :   static int maxNeighb = 10*10*10;
    3403           0 :   static bres_t **currClus = new bres_t*[maxNeighb];
    3404           0 :   static float* currCache = new float[maxNeighb*kVoxHDim];
    3405             :   //
    3406             :   //loop over neighbours which can contribute
    3407             :   //
    3408             :   //
    3409           0 :   int ix0,ip0,iz0;
    3410           0 :   FindVoxel(x,p, isect<kNSect ? z : -z, ix0,ip0,iz0); // find nearest voxel
    3411           0 :   bres_t* sectData = fSectGVoxRes[isect];
    3412           0 :   int binCen = GetVoxGBin(ix0,ip0,iz0);  // global bin of nearest voxel
    3413           0 :   bres_t* voxCen = &sectData[binCen]; // nearest voxel
    3414             :   //
    3415           0 :   int maxTrials[kVoxDim];
    3416           0 :   maxTrials[kVoxZ] = fNBins[kVoxZ]/2;
    3417           0 :   maxTrials[kVoxF] = fNBins[kVoxF]/2;
    3418           0 :   maxTrials[kVoxX] = fMaxBadXBinsToCover*2;
    3419             : 
    3420           0 :   int trial[kVoxDim]={0};
    3421           0 :   while(1)  {
    3422             :     //
    3423           0 :     memset(fLastSmoothingRes,0,kResDim*kMaxSmtDim*sizeof(double));
    3424           0 :     memset(cmat,0,kResDim*kMaxSmtDim*(kMaxSmtDim+1)/2*sizeof(double));
    3425             :     //
    3426             :     int nbOK=0; // accounted neighbours
    3427             :     //
    3428           0 :     float stepX = fStepKern[kVoxX]*(1. + kTrialStep*trial[kVoxX]);
    3429           0 :     float stepF = fStepKern[kVoxF]*(1. + kTrialStep*trial[kVoxF]);
    3430           0 :     float stepZ = fStepKern[kVoxZ]*(1. + kTrialStep*trial[kVoxZ]);
    3431             :     //
    3432           0 :     if (!(voxCen->flags&kDistDone) || (voxCen->flags&kMasked) || GetXBinIgnored(isect,ix0)) { 
    3433             :       // closest voxel has no data, increase smoothing step
    3434           0 :       stepX+=kTrialStep*fStepKern[kVoxX];
    3435           0 :       stepF+=kTrialStep*fStepKern[kVoxF];
    3436           0 :       stepZ+=kTrialStep*fStepKern[kVoxZ];
    3437           0 :     }
    3438             :     //
    3439             :     // effective kernel widths accounting for the increased bandwidth at the edges and missing data
    3440           0 :     float kWXI = GetDXI(ix0)  *fKernelWInv[kVoxX]*fStepKern[kVoxX]/stepX;
    3441           0 :     float kWFI = GetDY2XI(ix0)*fKernelWInv[kVoxF]*fStepKern[kVoxF]/stepF;
    3442           0 :     float kWZI = GetDZ2XI()   *fKernelWInv[kVoxZ]*fStepKern[kVoxZ]/stepZ;
    3443           0 :     int istepX = TMath::Nint(stepX+0.5);
    3444           0 :     int istepF = TMath::Nint(stepF+0.5);
    3445           0 :     int istepZ = TMath::Nint(stepZ+0.5);
    3446             :     // for edge bins increase kernel size and neighbours search
    3447           0 :     int ixMn=ix0-istepX,ixMx=ix0+istepX;
    3448           0 :     if (ixMn<0) {
    3449             :       ixMn = 0;
    3450           0 :       ixMx = TMath::Min(TMath::Nint(ix0+stepX*fKernelScaleEdge[kVoxX]),fNXBins-1);
    3451           0 :       kWXI /= fKernelScaleEdge[kVoxX];
    3452           0 :     }
    3453           0 :     if (ixMx>=fNXBins) {
    3454           0 :       ixMx = fNXBins-1;
    3455           0 :       ixMn = TMath::Max(TMath::Nint(ix0-stepX*fKernelScaleEdge[kVoxX]),0);
    3456           0 :       kWXI /= fKernelScaleEdge[kVoxX];
    3457           0 :     }
    3458             :     //
    3459           0 :     int ipMn=ip0-istepF,ipMx=ip0+istepF;
    3460           0 :     if (ipMn<0) {
    3461             :       ipMn = 0;
    3462           0 :       ipMx = TMath::Min(TMath::Nint(ip0+stepF*fKernelScaleEdge[kVoxF]),fNY2XBins-1);
    3463           0 :       kWFI /= fKernelScaleEdge[kVoxF];
    3464           0 :     }
    3465           0 :     if (ipMx>=fNY2XBins) {
    3466           0 :       ipMx = fNY2XBins-1; 
    3467           0 :       ipMn = TMath::Max(TMath::Nint(ip0-stepF*fKernelScaleEdge[kVoxF]),0);
    3468           0 :       kWFI /= fKernelScaleEdge[kVoxF];
    3469           0 :     }
    3470             :     //
    3471           0 :     int izMn=iz0-istepZ,izMx=iz0+istepZ;
    3472           0 :     if (izMn<0) {
    3473             :       izMn = 0;
    3474           0 :       izMx = TMath::Min(TMath::Nint(iz0+stepZ*fKernelScaleEdge[kVoxZ]),fNZ2XBins-1);
    3475           0 :       kWZI /= fKernelScaleEdge[kVoxZ];
    3476           0 :     }
    3477           0 :     if (izMx>=fNZ2XBins) {
    3478           0 :       izMx = fNZ2XBins-1;
    3479           0 :       izMn = TMath::Max(TMath::Nint(iz0-stepZ*fKernelScaleEdge[kVoxZ]),0);
    3480           0 :       kWZI /= fKernelScaleEdge[kVoxZ];
    3481           0 :     }
    3482             :     //
    3483           0 :     int nOccX[ixMx-ixMn+1],nOccF[ipMx-ipMn+1],nOccZ[izMx-izMn+1];
    3484             :     //
    3485             :     // check if cache arrays should be expanded
    3486           0 :     int nbCheck = (ixMx-ixMn+1)*(ipMx-ipMn+1)*(izMx-izMn+1);
    3487           0 :     if (nbCheck>=maxNeighb) { // need to expand caches
    3488           0 :       int mxNb = nbCheck+100;
    3489           0 :       delete[] currClus;
    3490           0 :       delete[] currCache;
    3491           0 :       currClus = new bres_t*[mxNb];
    3492           0 :       currCache= new float[mxNb*kVoxHDim];
    3493           0 :       maxNeighb = mxNb;
    3494           0 :     }
    3495             :     //
    3496           0 :     for (int i=ixMx-ixMn+1;i--;) nOccX[i]=0;
    3497           0 :     for (int i=ipMx-ipMn+1;i--;) nOccF[i]=0;
    3498           0 :     for (int i=izMx-izMn+1;i--;) nOccZ[i]=0;
    3499           0 :     double u2Vec[3];
    3500             :     //1st loop, check presence of enough points, cache precalculated values
    3501           0 :     float *cacheVal = currCache;
    3502           0 :     for (int ix=ixMn;ix<=ixMx;ix++) {
    3503           0 :       for (int ip=ipMn;ip<=ipMx;ip++) {
    3504           0 :         for (int iz=izMn;iz<=izMx;iz++) {
    3505             :           //
    3506           0 :           int binNb = GetVoxGBin(ix,ip,iz);  // global bin
    3507           0 :           bres_t* voxNb = &sectData[binNb];
    3508           0 :           if (!(voxNb->flags&kDistDone) || (voxNb->flags&kMasked) || GetXBinIgnored(isect,ix)) continue; // skip voxels w/o data
    3509             :           // estimate weighted distance
    3510           0 :           float dx = voxNb->stat[kVoxX]-x;
    3511           0 :           float df = voxNb->stat[kVoxF]-p;
    3512           0 :           float dz = voxNb->stat[kVoxZ]-z;
    3513           0 :           float dxw = dx*kWXI, dfw = df*kWFI, dzw = dz*kWZI;
    3514           0 :           u2Vec[0] = dxw*dxw;
    3515           0 :           u2Vec[1] = dfw*dfw;
    3516           0 :           u2Vec[2] = dzw*dzw;
    3517           0 :           double kernW = GetKernelWeight(u2Vec,3);
    3518           0 :           if (kernW<kZeroK) continue; 
    3519             :           // new point is validated       
    3520           0 :           nOccX[ix-ixMn]++;
    3521           0 :           nOccF[ip-ipMn]++;
    3522           0 :           nOccZ[iz-izMn]++;
    3523           0 :           currClus[nbOK] = voxNb;
    3524           0 :           cacheVal[kVoxX] = dx;
    3525           0 :           cacheVal[kVoxF] = df;
    3526           0 :           cacheVal[kVoxZ] = dz;
    3527           0 :           cacheVal[kVoxV] = kernW;
    3528           0 :           cacheVal += kVoxHDim;
    3529           0 :           nbOK++;
    3530           0 :         }
    3531             :       }
    3532             :     }
    3533             :     //
    3534             :     // check if we have enough points in every dimension
    3535           0 :     int np[kVoxDim]={0};
    3536           0 :     for (int i=ixMx-ixMn+1;i--;) if (nOccX[i]) np[kVoxX]++; 
    3537           0 :     for (int i=ipMx-ipMn+1;i--;) if (nOccF[i]) np[kVoxF]++;
    3538           0 :     for (int i=izMx-izMn+1;i--;) if (nOccZ[i]) np[kVoxZ]++;
    3539           0 :     Bool_t enoughPoints = kTRUE, incrDone[kVoxDim] = {0};
    3540           0 :     for (int i=0;i<kVoxDim;i++) {
    3541           0 :       if (np[i]<minPointsDir[i]) { // need to extend smoothing neighborhood
    3542             :         enoughPoints=kFALSE;
    3543           0 :         if (trial[i]<maxTrials[i] && !incrDone[i]) { //try to increment only missing direction
    3544           0 :           trial[i]++; incrDone[i]=kTRUE;
    3545           0 :         } 
    3546           0 :         else if (trial[i]==maxTrials[i]) { // cannot increment missing direction, try others
    3547           0 :           for (int j=kVoxDim;j--;) {
    3548           0 :             if (i!=j && trial[j]<maxTrials[j] && !incrDone[j]) {
    3549           0 :               trial[j]++; incrDone[j]=kTRUE;
    3550           0 :             }
    3551             :           }
    3552           0 :         }
    3553             :       }
    3554             :     }
    3555           0 :     if (!enoughPoints) {
    3556           0 :       if (!(incrDone[kVoxX]||incrDone[kVoxF]||incrDone[kVoxZ])) {
    3557           0 :         AliErrorF("Voxel Z:%d F:%d X:%d Trials limit reached: Z:%d F:%d X:%d",
    3558             :                   voxCen->bvox[kVoxZ],voxCen->bvox[kVoxF],voxCen->bvox[kVoxX],
    3559             :                   trial[kVoxZ],trial[kVoxF],trial[kVoxX]);
    3560           0 :         return kFALSE;
    3561             :       }
    3562             :       /*
    3563             :         AliWarningF("Sector:%2d x=%.3f y/x=%.3f z/x=%.3f (iX:%d iY2X:%d iZ2X:%d)\n"
    3564             :         "not enough neighbours (need min %d) %d %d %d (tot: %d) | Steps: %.1f %.1f %.1f\n"
    3565             :         "trying to increase filter bandwidth (trialXFZ:%d %d %d)\n",
    3566             :         isect,x,p,z,ix0,ip0,iz0,2,np[kVoxX],np[kVoxF],np[kVoxZ],nbOK,stepX,stepF,stepZ,
    3567             :         trial[kVoxX],trial[kVoxF],trial[kVoxZ]);
    3568             :       */
    3569           0 :       continue;
    3570             :     }
    3571             :     //
    3572             :     // now fill the matrices and solve 
    3573           0 :     cacheVal = currCache;
    3574           0 :     for (int ib=0;ib<nbOK;ib++) {
    3575           0 :       double kernW = cacheVal[kVoxV];
    3576           0 :       double dx=cacheVal[kVoxX], df=cacheVal[kVoxF], dz=cacheVal[kVoxZ],dx2=dx*dx, df2=df*df, dz2 = dz*dz;
    3577           0 :       cacheVal += kVoxHDim;
    3578           0 :       const bres_t* voxNb = currClus[ib];
    3579           0 :       for (int id=0;id<kResDim;id++) {
    3580           0 :         if (!doDim[id]) continue;
    3581             :         double kernWD = kernW;
    3582           0 :         if (fUseErrInSmoothing) kernWD /= (voxNb->E[id]*voxNb->E[id]); // apart from the kernel value, account for the point error
    3583           0 :         double *cmatD = cmat[id];
    3584           0 :         double *rhsD = &fLastSmoothingRes[id*kMaxSmtDim];
    3585             :         //
    3586           0 :         double kernWDx=kernWD*dx, kernWDf=kernWD*df, kernWDz=kernWD*dz;
    3587           0 :         double kernWDx2=kernWDx*dx, kernWDf2=kernWDf*df, kernWDz2=kernWDz*dz;
    3588             :         //
    3589             :         // linear part
    3590             :         int el=-1,elR=-1;
    3591           0 :         cmatD[++el] += kernWD;
    3592           0 :         rhsD[++elR] += kernWD*voxNb->D[id];
    3593             :         //
    3594           0 :         cmatD[++el] += kernWDx;   cmatD[++el] += kernWDx2;
    3595           0 :         rhsD[++elR] += kernWDx*voxNb->D[id];
    3596             :         //
    3597           0 :         cmatD[++el] += kernWDf;   cmatD[++el] += kernWDx*df;  cmatD[++el] += kernWDf2;
    3598           0 :         rhsD[++elR] += kernWDf*voxNb->D[id];
    3599             :         //
    3600           0 :         cmatD[++el] += kernWDz;   cmatD[++el] += kernWDx*dz;  cmatD[++el] += kernWDf*dz;   cmatD[++el] += kernWDz2;
    3601           0 :         rhsD[++elR] += kernWDz*voxNb->D[id];       
    3602             :         //
    3603             :         // check if quadratic part is needed
    3604           0 :         if (fSmoothPol2[kVoxX]) {
    3605           0 :           cmatD[++el] += kernWDx2;   cmatD[++el] += kernWDx2*dx; cmatD[++el] += kernWDf*dx2; cmatD[++el] += kernWDz*dx2; cmatD[++el] += kernWDx2*dx2;
    3606           0 :           rhsD[++elR] += kernWDx2*voxNb->D[id];
    3607           0 :         }
    3608           0 :         if (fSmoothPol2[kVoxF]) {
    3609           0 :           cmatD[++el] += kernWDf2;   cmatD[++el] += kernWDx*df2; cmatD[++el] += kernWDf*df2; cmatD[++el] += kernWDz*df2; cmatD[++el] += kernWDx2*df2; cmatD[++el] += kernWDf2*df2;
    3610           0 :           rhsD[++elR] += kernWDf2*voxNb->D[id];
    3611           0 :         }
    3612           0 :         if (fSmoothPol2[kVoxZ]) {
    3613           0 :           cmatD[++el] += kernWDz2;   cmatD[++el] += kernWDx*dz2; cmatD[++el] += kernWDf*dz2; cmatD[++el] += kernWDz*dz2; cmatD[++el] += kernWDx2*dz2; cmatD[++el] += kernWDf2*dz2; cmatD[++el] += kernWDz2*dz2;
    3614           0 :           rhsD[++elR] += kernWDz2*voxNb->D[id];
    3615           0 :         }
    3616           0 :       }
    3617             :     }
    3618             :     //
    3619             :     Bool_t fitRes = kTRUE;
    3620             :     //
    3621             :     // solve system of linear equations
    3622           0 :     AliSymMatrix mat(matSize);
    3623           0 :     for (int id=0;id<kResDim;id++) {
    3624           0 :       if (!doDim[id]) continue;
    3625           0 :       mat.Reset();
    3626           0 :       double *cmatD = cmat[id];
    3627           0 :       double *rhsD = &fLastSmoothingRes[id*kMaxSmtDim];
    3628             :       int el=-1,elR=-1,row=-1;
    3629           0 :       mat(++row,0) = cmatD[++el];
    3630           0 :       mat(++row,0) = cmatD[++el];   mat(row,1) = cmatD[++el];
    3631           0 :       mat(++row,0) = cmatD[++el];   mat(row,1) = cmatD[++el];  mat(row,2) = cmatD[++el]; 
    3632           0 :       mat(++row,0) = cmatD[++el];   mat(row,1) = cmatD[++el];  mat(row,2) = cmatD[++el];  mat(row,3) = cmatD[++el];
    3633             :       // pol2 elements if needed
    3634           0 :       if (fSmoothPol2[kVoxX]) {
    3635             :         const int colLim = (++row)+1;
    3636           0 :         for (int col=0;col<colLim;col++) mat(row,col) = cmatD[++el];
    3637           0 :       }
    3638           0 :       if (fSmoothPol2[kVoxF]) {
    3639           0 :         const int colLim = (++row)+1;
    3640           0 :         for (int col=0;col<colLim;col++) mat(row,col) = cmatD[++el];
    3641           0 :       }
    3642           0 :       if (fSmoothPol2[kVoxZ]) {
    3643           0 :         const int colLim = (++row)+1;
    3644           0 :         for (int col=0;col<colLim;col++) mat(row,col) = cmatD[++el];
    3645           0 :       }
    3646             :       //
    3647           0 :       fitRes &= mat.SolveChol(rhsD);
    3648           0 :       if (!fitRes) {
    3649           0 :         for (int i=kVoxDim;i--;) trial[i]++;
    3650           0 :         AliWarningF("Sector:%2d x=%.3f y/x=%.3f z/x=%.3f (iX:%d iY2X:%d iZ2X:%d)\n"
    3651             :                     "neighbours range used %d %d %d (tot: %d) | Steps: %.1f %.1f %.1f\n"
    3652             :                     "Solution for smoothing Failed, trying to increase filter bandwidth (trialXFZ: %d %d %d)",
    3653             :                     isect,x,p,z,ix0,ip0,iz0,np[kVoxX],np[kVoxF],np[kVoxZ],nbOK,stepX,stepF,stepZ,trial[kVoxX],trial[kVoxF],trial[kVoxZ]);
    3654           0 :         continue;
    3655             :       }
    3656           0 :       res[id] = rhsD[0];
    3657           0 :       if (deriv) for (int j=0;j<3;j++) deriv[id*3 +j] = rhsD[j+1]; // ignore eventual pol2 term
    3658           0 :     }
    3659             :     //
    3660             :     break; // success
    3661           0 :   } // end of loop over allowed trials
    3662             :   
    3663           0 :   return kTRUE;
    3664             : 
    3665           0 : }
    3666             : 
    3667             : //_____________________________________________________________________
    3668             : Bool_t AliTPCDcalibRes::GetSmooth1D
    3669             : (double xQuery,                                            // query X
    3670             :  double valerr[2],                                          // output array for value and its error
    3671             :  int np, const double* x, const double* y, const double* err, // points x,y, optional error 
    3672             :  double w, int kType,Bool_t usePol2,                       // kernel width and type, do we use pol1 or pol2 interpolation
    3673             :  Bool_t xIncreasing,                                       // are points increasing in X
    3674             :  float  maxD2Range                                         // may increase kernel width up to maxD2Range*dataRange
    3675             :  ) const 
    3676             : {
    3677             :   // get kernel (width w) smoothed value at xQuery for (opionally ordered in x-increasing) array x,y (optionally err)
    3678           0 :   int minPoints = 3+usePol2;
    3679             :   // don't abuse stack
    3680           0 :   float *ySelHeap=0,ySelStack[np<kMaxOnStack ? np:1],*ySel=np<kMaxOnStack ? &ySelStack[0] : (ySelHeap=new float[np]);
    3681           0 :   float *xSelHeap=0,xSelStack[np<kMaxOnStack ? np:1],*xSel=np<kMaxOnStack ? &xSelStack[0] : (xSelHeap=new float[np]);
    3682           0 :   float *wSelHeap=0,wSelStack[np<kMaxOnStack ? np:1],*wSel=np<kMaxOnStack ? &wSelStack[0] : (wSelHeap=new float[np]);
    3683             :   //
    3684             :   // select only points which have chance to contribute
    3685             :   double ws = w;
    3686           0 :   double xmax = x[np-1], xmin = x[0];
    3687           0 :   if (!xIncreasing) {
    3688           0 :     for (int i=np;i--;) {
    3689           0 :       if (xmax>x[i]) xmax = x[i];
    3690           0 :       if (xmin<x[i]) xmin = x[i];
    3691             :     }
    3692           0 :   }
    3693           0 :   double maxD,w2Sum=0.,range = (xmax - xmin)*maxD2Range;
    3694             :   //
    3695             :   const float kEps = 1e-12;
    3696             :   int npUse=0;
    3697           0 :   do {
    3698           0 :     maxD = ws*(kType==kGaussianKernel ? kMaxGaussStdDev : 1.0f);
    3699           0 :     double ws2 = 1./(ws*ws);
    3700             :     npUse = 0;
    3701             :     w2Sum = 0.;
    3702           0 :     for (int ip=0;ip<np;ip++) {
    3703           0 :       double df = x[ip]-xQuery;
    3704           0 :       if (df>maxD) {
    3705           0 :         if (xIncreasing) break; // with sorted arrays no point in checking further
    3706           0 :         continue;
    3707             :       }
    3708           0 :       if (df<-maxD) continue;
    3709           0 :       xSel[npUse] = df;  // we fit wrt queried point!
    3710           0 :       ySel[npUse] = y[ip];
    3711           0 :       df *= df*ws2;
    3712           0 :       wSel[npUse] = GetKernelWeight(&df,1);
    3713           0 :       w2Sum += wSel[npUse];
    3714           0 :       if (wSel[npUse]<kEps) continue; 
    3715           0 :       if (err && err[ip]>0) wSel[npUse] /= err[ip]*err[ip];
    3716           0 :       npUse++;
    3717           0 :     }
    3718             :     //
    3719           0 :     if (npUse>=minPoints) break;
    3720           0 :     ws *= 1.5; // expand kernel
    3721           0 :   }
    3722           0 :   while (maxD<range);
    3723             :   //
    3724             :   Bool_t res = kFALSE;
    3725           0 :   if (npUse<minPoints) {
    3726           0 :     valerr[0] = valerr[1] = 0.f;
    3727           0 :     AliErrorF("Found only %d points, %d required",npUse,minPoints);
    3728           0 :   }
    3729             :   else {
    3730           0 :     float resVal[3],resErr[6];
    3731           0 :     if ((res=usePol2 ? FitPoly2(xSel,ySel,wSel,npUse,resVal,resErr) : FitPoly1(xSel,ySel,wSel,npUse,resVal,resErr))) {
    3732           0 :       valerr[0] = resVal[0];
    3733           0 :       valerr[1] = TMath::Sqrt(resErr[0]/w2Sum);
    3734           0 :     }
    3735           0 :   }
    3736           0 :   delete[] ySelHeap;
    3737           0 :   delete[] xSelHeap;
    3738           0 :   delete[] wSelHeap;
    3739             :   //
    3740           0 :   return res;
    3741           0 : }
    3742             : 
    3743             : //_____________________________________
    3744             : Double_t AliTPCDcalibRes::GetKernelWeight(double* u2vec,int np) const
    3745             : {
    3746             :   double w = 1;
    3747           0 :   if (fKernelType == kEpanechnikovKernel) {
    3748           0 :     for (int i=np;i--;) {
    3749           0 :       if (u2vec[i]>1) return 0.;
    3750           0 :       w *= 3./4.*(1.-u2vec[i]);
    3751             :     }
    3752             :   }
    3753           0 :   else if (fKernelType == kGaussianKernel) {
    3754             :     double u2 = 0;
    3755           0 :     for (int i=np;i--;) u2 += u2vec[i];
    3756           0 :     w = u2<kMaxGaussStdDev*kMaxGaussStdDev*np ? TMath::Exp(-u2)/TMath::Sqrt(2.*TMath::Pi()) : 0;
    3757           0 :   }
    3758             :   else {
    3759           0 :     AliFatalF("Kernel type %d is not defined",fKernelType);
    3760             :   }
    3761           0 :   return w;
    3762           0 : }
    3763             : 
    3764             : 
    3765             : //_____________________________________
    3766             : void AliTPCDcalibRes::SetKernelType(int tp, float bwX, float bwP, float bwZ, float scX,float scP,float scZ)
    3767             : {
    3768             :   // set kernel type and widths in terms of binning in X,Y/X and Z/X, define aux variables
    3769           0 :   fKernelType = tp;
    3770             :   //
    3771           0 :   fKernelScaleEdge[kVoxX] = scX;
    3772           0 :   fKernelScaleEdge[kVoxF] = scP;
    3773           0 :   fKernelScaleEdge[kVoxZ] = scZ;
    3774             : 
    3775           0 :   fKernelWInv[kVoxX] = bwX>0 ? 1./bwX : 1.;
    3776           0 :   fKernelWInv[kVoxF] = bwP>0 ? 1./bwP : 1.;
    3777           0 :   fKernelWInv[kVoxZ] = bwZ>0 ? 1./bwZ : 1.;
    3778             : 
    3779           0 :   if (fKernelType == kEpanechnikovKernel) { // bandwidth 1
    3780           0 :     fStepKern[kVoxX] = TMath::Nint(bwX+0.5);
    3781           0 :     fStepKern[kVoxF] = TMath::Nint(bwP+0.5);
    3782           0 :     fStepKern[kVoxZ] = TMath::Nint(bwZ+0.5);    
    3783           0 :   }
    3784             :   else if (kGaussianKernel) {  // look in ~5 sigma
    3785           0 :     fStepKern[kVoxX] = TMath::Nint(bwX*5.+0.5);
    3786           0 :     fStepKern[kVoxF] = TMath::Nint(bwP*5.+0.5);
    3787           0 :     fStepKern[kVoxZ] = TMath::Nint(bwZ*5.+0.5);
    3788             :   }
    3789             :   else {
    3790             :     AliFatalF("Kernel type %d is not defined",fKernelType);
    3791             :   }
    3792           0 :   for (int i=kVoxDim;i--;) if (fStepKern[i]<1) fStepKern[i] = 1;
    3793             :   //
    3794           0 : }
    3795             : 
    3796             : 
    3797             : //=========================================================================
    3798             : 
    3799             : //_____________________________________________
    3800             : void AliTPCDcalibRes::CreateCorrectionObject()
    3801             : {
    3802             :   // create correction object for given time slice
    3803             : 
    3804           0 :   AliSysInfo::AddStamp("CreateCorrectionObject",0,0,0,0);
    3805             :   //  
    3806             :   // check if there are failures
    3807             :   Bool_t create = kTRUE;
    3808           0 :   for (int i=0;i<kNSect2;i++) {
    3809           0 :     if (fNSmoothingFailedBins[i]>0) {
    3810           0 :       AliErrorF("%d failed voxels in sector %d",fNSmoothingFailedBins[i],i); 
    3811             :       create = kFALSE;
    3812           0 :     }
    3813             :   }
    3814             :   //
    3815           0 :   if (!create) {
    3816           0 :     AliError("ATTENTION: MAP WILL NOT BE CREATED");
    3817           0 :     return;
    3818             :   }
    3819             :   //
    3820           0 :   TString name = Form("run%d_%lld_%lld",fRun,fTMin,fTMax);
    3821           0 :   fChebCorr = new AliTPCChebCorr(name.Data(),name.Data(),
    3822           0 :                                  fChebPhiSlicePerSector,fChebZSlicePerSide,1.0f);
    3823           0 :   fChebCorr->SetUseFloatPrec(kFALSE);
    3824           0 :   fChebCorr->SetRun(fRun);
    3825           0 :   fChebCorr->SetTimeStampStart(fTMin);
    3826           0 :   fChebCorr->SetTimeStampEnd(fTMax);
    3827           0 :   fChebCorr->SetTimeDependent(kFALSE);
    3828           0 :   fChebCorr->SetUseZ2R(kTRUE);
    3829             :   //
    3830           0 :   if      (fBz> 0.01) fChebCorr->SetFieldType(AliTPCChebCorr::kFieldPos);
    3831           0 :   else if (fBz<-0.01) fChebCorr->SetFieldType(AliTPCChebCorr::kFieldNeg);
    3832           0 :   else                fChebCorr->SetFieldType(AliTPCChebCorr::kFieldZero);
    3833             :   // Note: to create universal map, set manually SetFieldType(AliTPCChebCorr::kFieldAny)
    3834             : 
    3835           0 :   SetUsedInstance(this);
    3836           0 :   int npCheb[kResDim][2];
    3837           0 :   for (int i=0;i<kResDim;i++) { // do we need to determine N nodes automatically?
    3838           0 :     int nbFauto = TMath::Max(int(fNY2XBins*1.2),fNY2XBins+3);
    3839           0 :     int nbZauto = TMath::Max(int(fNZ2XBins*1.2),fNZ2XBins+3);
    3840           0 :     npCheb[i][0] = fNPCheb[i][0];
    3841           0 :     npCheb[i][1] = fNPCheb[i][1];
    3842           0 :     if (npCheb[i][0]<1) {
    3843           0 :       npCheb[i][0] = nbFauto; // 1st dimension: sector coordinate y/x
    3844           0 :       AliInfoF("Nnodes for Cheb.%4s segmentation in %4s is set to %2d",kResName[i],kVoxName[kVoxF],nbFauto);
    3845           0 :     }
    3846           0 :     if (npCheb[i][1]<1) {
    3847           0 :       npCheb[i][1] = nbZauto; // 2nd dimension: z/x
    3848           0 :       AliInfoF("Nnodes for Cheb.%4s segmentation in %4s is set to %2d",kResName[i],kVoxName[kVoxZ],nbZauto);
    3849           0 :     }
    3850             :   }
    3851           0 :   fChebCorr->Parameterize(trainCorr,kResDim,npCheb,fChebPrecD);
    3852             :   //
    3853             :   // register tracks rate for lumi weighting
    3854           0 :   fChebCorr->SetTracksRate(ExtractTrackRate());
    3855             :   //
    3856             :   // calculate weighted lumi
    3857           0 :   fLumiCTPGraph = AliLumiTools::GetLumiFromCTP(fRun);
    3858           0 :   fLumiCOG = fChebCorr->GetLuminosityCOG(fLumiCTPGraph);
    3859             :   //
    3860           0 :   AliSysInfo::AddStamp("CreateCorrectionObject",1,0,0,0);
    3861           0 : }
    3862             : 
    3863             : //________________________________________________________________
    3864             : TH1F* AliTPCDcalibRes::ExtractTrackRate() const
    3865             : {
    3866             :   // create histo with used tracks per timestamp
    3867             :   TH1F* hTr = 0;
    3868           0 :   if (fTracksRate) { 
    3869           0 :     const float *tarr = fTracksRate->GetArray();
    3870           0 :     int nb = fTracksRate->GetNbinsX();
    3871             :     int bin0=1,bin1=nb;
    3872           0 :     while(tarr[bin0]<0.5 && bin0<=nb) bin0++; // find first significant time bin 
    3873           0 :     while(tarr[bin1]<0.5 && bin1>=bin0) bin1--; // find last significant time bin
    3874           0 :     nb = bin1 - bin0 + 1;
    3875           0 :     Long64_t tmn = (Long64_t)fTracksRate->GetBinCenter(bin0);
    3876           0 :     Long64_t tmx = (Long64_t)fTracksRate->GetBinCenter(bin1);
    3877           0 :     hTr = new TH1F(Form("TrackRate%lld_%lld",tmn,tmx),"TracksRate",nb,
    3878           0 :                    fTracksRate->GetBinLowEdge(bin0),fTracksRate->GetBinLowEdge(bin1+1));
    3879           0 :     hTr->SetDirectory(0);
    3880           0 :     for (int ib=0;ib<nb;ib++) {
    3881           0 :       int ibh = ib+bin0;
    3882           0 :       hTr->SetBinContent(ib+1,tarr[ibh]);
    3883             :     }
    3884           0 :   }
    3885           0 :   else AliError("TracksRate accumulation histo was not initialized");
    3886           0 :   return hTr;
    3887           0 : }
    3888             : 
    3889             : //________________________________________________________________
    3890             : void AliTPCDcalibRes::InitBinning()
    3891             : {
    3892             :   // initialize binning structures
    3893             :   //
    3894             :   // X binning
    3895           0 :   if (fNXBins>0 && fNXBins<kNPadRows) {
    3896           0 :     AliInfoF("X-binning: uniform %d bins from %.2f to %.2f",fNXBins,kMinX,kMaxX);
    3897           0 :     fDXI         = fNXBins/(kMaxX-kMinX);
    3898           0 :     fDX          = 1.0f/fDXI;
    3899           0 :     fUniformBins[kVoxX] = kTRUE;
    3900           0 :   }
    3901             :   else {
    3902           0 :     fNXBins = kNPadRows;
    3903           0 :     AliInfo("X-binning: bin per pad-row");
    3904           0 :     fUniformBins[kVoxX] = kFALSE;
    3905           0 :     fDX = kTPCRowDX[0];
    3906           0 :     fDXI = 1.f/fDX; // should not be used
    3907             :   }
    3908             :   //
    3909             :   // Y binning
    3910           0 :   if (fNXBins<1) AliFatal("X bins must be initialized first");
    3911           0 :   fMaxY2X = new Float_t[fNXBins];        // max Y/X at each X bin, account for dead zones
    3912           0 :   fDY2XI  = new Float_t[fNXBins];        // inverse of Y/X bin size at given X bin
    3913           0 :   fDY2X   = new Float_t[fNXBins];        // Y/X bin size at given X bin
    3914             :   //
    3915           0 :   const float kMaxY2X = TMath::Tan(0.5f*kSecDPhi);
    3916             : 
    3917           0 :   for (int ix=0;ix<fNXBins;ix++) {
    3918           0 :     float x = GetX(ix);
    3919           0 :     fMaxY2X[ix] = kMaxY2X - kDeadZone/x;
    3920           0 :     fDY2XI[ix] = fNY2XBins / (2.f*fMaxY2X[ix]);
    3921           0 :     fDY2X[ix] = 1.f/fDY2XI[ix];
    3922             :   }
    3923             :   //
    3924           0 :   fDZ2XI = fNZ2XBins/kMaxZ2X;
    3925           0 :   fDZ2X  = 1.0f/fDZ2XI;
    3926             :   //
    3927           0 :   fNBins[kVoxX] = fNXBins;
    3928           0 :   fNBins[kVoxF] = fNY2XBins;
    3929           0 :   fNBins[kVoxZ] = fNZ2XBins;
    3930             : 
    3931           0 :   fNGVoxPerSector = fNY2XBins*fNZ2XBins*fNXBins;
    3932             : 
    3933           0 : }
    3934             : 
    3935             : //________________________________________________________________
    3936             : Int_t AliTPCDcalibRes::GetXBin(float x) 
    3937             : {
    3938             :   // convert X to bin ID, following pad row widths
    3939           0 :   if (fUniformBins[kVoxX]) {
    3940           0 :     int ix = (x-kMinX)*fDXI;
    3941           0 :     if (ix<0) return 0;
    3942           0 :     else if (ix>=fNXBins) return fNXBins-1;
    3943           0 :     return ix;
    3944             :   }
    3945             :   else {
    3946             :     int ix;
    3947           0 :     if (x<kTPCRowX[kNRowIROC-1]+0.5*kTPCRowDX[kNRowIROC-1]) {     // uniform pad size in IROC
    3948           0 :       ix = (x-(kTPCRowX[0]-kTPCRowDX[0]*0.5))/kTPCRowDX[0];
    3949           0 :       if (ix<0) ix = 0;
    3950           0 :     }
    3951             :     // uniform pad size in OROC2
    3952           0 :     else if ( x>= kTPCRowX[kNRowIROC+kNRowOROC1]-0.5*kTPCRowDX[kNRowIROC+kNRowOROC1] ) {
    3953           0 :       ix = (x-(kTPCRowX[kNRowIROC+kNRowOROC1]-0.5*kTPCRowDX[kNRowIROC+kNRowOROC1]))/kTPCRowDX[kNPadRows-1]
    3954           0 :         + kNRowIROC + kNRowOROC1;
    3955           0 :       if (ix>=kNPadRows) ix = kNPadRows-1;
    3956           0 :     }
    3957             :     else { // uniform pad size in OROC1
    3958           0 :       ix = (x-(kTPCRowX[kNRowIROC]-0.5*kTPCRowDX[kNRowIROC]))/kTPCRowDX[kNRowIROC] + kNRowIROC;
    3959           0 :       if (ix<kNRowIROC) { // we go between IROC and OROC?
    3960           0 :         if (x> 0.5*(kTPCRowX[kNRowIROC-1]+kTPCRowX[kNRowIROC]))  ix = kNRowIROC; // 1st OROC1 row
    3961             :         else ix = kNRowIROC-1;
    3962             :       }
    3963             :       
    3964             :     }
    3965             :     return ix;
    3966             :     // 
    3967             :   }
    3968           0 : }
    3969             : 
    3970             : //________________________________________________________________
    3971             : Int_t AliTPCDcalibRes::GetRowID(float x)
    3972             : {
    3973             :   // return row ID
    3974             :   int ix;
    3975           0 :   if (x<kTPCRowX[kNRowIROC-1]+0.5*kTPCRowDX[kNRowIROC-1]) {     // uniform pad size in IROC
    3976           0 :     ix = (x-(kTPCRowX[0]-kTPCRowDX[0]*0.5))/kTPCRowDX[0];
    3977           0 :     if (ix<0) ix = -1;
    3978           0 :   }
    3979             :   // uniform pad size in OROC2
    3980           0 :   else if ( x>= kTPCRowX[kNRowIROC+kNRowOROC1]-0.5*kTPCRowDX[kNRowIROC+kNRowOROC1] ) {
    3981           0 :     ix = (x-(kTPCRowX[kNRowIROC+kNRowOROC1]-0.5*kTPCRowDX[kNRowIROC+kNRowOROC1]))/kTPCRowDX[kNPadRows-1]
    3982           0 :       + kNRowIROC + kNRowOROC1;
    3983           0 :     if (ix>=kNPadRows) ix = -2;
    3984           0 :   }
    3985             :   else { // uniform pad size in OROC1
    3986           0 :     ix = (x-(kTPCRowX[kNRowIROC]-0.5*kTPCRowDX[kNRowIROC]))/kTPCRowDX[kNRowIROC] + kNRowIROC;
    3987           0 :     if (ix<kNRowIROC) { // we go between IROC and OROC?
    3988             :       ix = -3;
    3989             :     }
    3990             :     
    3991             :   }
    3992           0 :   return ix;
    3993             : }
    3994             : 
    3995             : //_____________________________________________________
    3996             : Bool_t AliTPCDcalibRes::FindVoxelBin(int sectID, float x, float y, float z, UChar_t bin[kVoxHDim],float voxVars[kVoxHDim])
    3997             : {
    3998             :   // define voxel variables and bin
    3999             :   //  
    4000             :   //
    4001             :   // track Z/X bin
    4002           0 :   voxVars[kVoxZ] = z/x;
    4003           0 :   if (TMath::Abs(voxVars[kVoxZ])>kMaxZ2X) return kFALSE;
    4004           0 :   int binZ       = GetZ2XBinExact( sectID<kNSect ? voxVars[kVoxZ] : -voxVars[kVoxZ] );
    4005           0 :   if (binZ<0) return kFALSE;
    4006           0 :   bin[kVoxZ] = binZ;
    4007             :   //
    4008             :   // track X bin
    4009           0 :   voxVars[kVoxX] = x;
    4010           0 :   int binX = GetXBinExact(x); // exact matching to pad-rows
    4011           0 :   if (binX<0 || binX>=fNXBins) return kFALSE;
    4012           0 :   bin[kVoxX] = binX;
    4013             :   //
    4014             :   // track Y/X bin accounting for sector edges dead zones
    4015           0 :   voxVars[kVoxF] = y/x;
    4016           0 :   int binF = GetY2XBinExact(voxVars[kVoxF],binX);
    4017           0 :   if (binF<0||binF>=fNY2XBins) return kFALSE;
    4018           0 :   bin[kVoxF] = binF;
    4019             :   //
    4020           0 :   return kTRUE;
    4021           0 : }
    4022             : 
    4023             : //=====================================================================
    4024             : ///////////////////////////////////////////////////
    4025             : //
    4026             : // This is a special non-meber f-n for cheb. learning
    4027             : //
    4028             : void trainCorr(int row, float* tzLoc, float* corrLoc)
    4029             : {
    4030             :   // Cheb. object training f-n: compute correction for the point
    4031             :   //
    4032             :   // xtzLoc: y2x and z2x in sector frame
    4033             :   // corrLoc: x, y, z corrections in sector frame
    4034             :   // when called with pointer at 0, row will set the sector/side 
    4035             :   // (row should be sector in 0-35 or 0-71 format)
    4036             :   static int sector=0;
    4037           0 :   if (!tzLoc || !corrLoc) {
    4038           0 :     sector = row%AliTPCDcalibRes::kNSect2; 
    4039           0 :     printf("training Sector%d\n",sector);
    4040           0 :     return;
    4041             :   }
    4042             :   //
    4043           0 :   AliTPCDcalibRes* calib = AliTPCDcalibRes::GetUsedInstance();
    4044             : 
    4045           0 :   float x = AliTPCDcalibRes::GetTPCRowX(row);
    4046           0 :   float dist[AliTPCDcalibRes::kResDim] = {0};
    4047           0 :   int xbin = calib->GetNXBins()==AliTPCDcalibRes::kNPadRows ? row : calib->GetXBin(x);
    4048           0 :   if (calib->GetXBinIgnored(sector,xbin)) return;
    4049           0 :   float y2x = tzLoc[0];
    4050           0 :   float z2x = tzLoc[1];
    4051             :   //
    4052           0 :   Bool_t res = calib->GetSmoothEstimate(sector, x, y2x, z2x, 0xff, dist);
    4053           0 :   if (!res) { printf("Failed to evaluate smooth distortion\n"); exit(1); }
    4054             : 
    4055             :   /*
    4056             :   // Marian stored Z track coordinate instead of cluster one, need to correct for this
    4057             :   if (fApplyZt2Zc) {
    4058             :     float deriv[AliTPCDcalibRes::kResDim*3];
    4059             :     const double inversionEps = 20e-4; // when inverting, stop Newton-Raphson iterations at this eps
    4060             :     const int    inversionMaxIt = 3; // when inverting, stop Newton-Raphson after some numbers of iterations
    4061             :     double change = 0, xInv = 1./x;
    4062             :     float zc = z2x*x;
    4063             :     float zt = zc + dist[kResZ]; // 1st guess on true zt at measured zc
    4064             :     //
    4065             :     // use Newton-Raphson method for NDLocal inversion to get zt = F(zc) from 
    4066             :     // dz == zt - zc = NDLoc(zt)   ->  zc - [zt - NDLoc(zt)]=0 
    4067             :     // ->  zt_{i+1} = zt_i - (zc - [zt - NDLoct(zt_i)])/(-d[zt_i-NDLoc(zt_i)]/dz)
    4068             :     //
    4069             :     int it = 0;
    4070             :     do {
    4071             :       z2x = zt*xInv;
    4072             :       res = GetSmoothEstimate(sector, x, y2x, z2x, dist, deriv);
    4073             :       if (!res) {printf("Failed to evaluate smooth distortion\n");exit(1);}
    4074             :       double bot = 1. - deriv[kResZ*3+2]*xInv;  // dF(zt_i)/dz
    4075             :       if (TMath::Abs(bot)<1e-6) break;
    4076             :       double top = zc - (zt - dist[kResZ]); // zc - F(zt_i) 
    4077             :       double change = top/bot;
    4078             :       //  printf("It %d Eps:%+e, Zc:%+e, Zt:%+e Ztn:%+e DZ:%+e | dztmp: :%+e DD:%+e\n",
    4079             :       //     it,change,zc,zt,zt+change,dz,dztmp,deriv[kndZ2R]*xInv);
    4080             :       zt += change;
    4081             :       it++;
    4082             :     } while(it<inversionMaxIt && TMath::Abs(change)>inversionEps);
    4083             :     //
    4084             :     // now query at fixed Z2X
    4085             :     z2x = zt*xInv;
    4086             :     res = GetSmoothEstimate(sector, x, y2x, z2x, dist);
    4087             :     if (!res) {printf("Failed to evaluate smooth distortion\n");exit(1);}
    4088             :   }
    4089             :   */
    4090             : 
    4091           0 :   for (int i=0;i<AliTPCDcalibRes::kResDim;i++) corrLoc[i] = dist[i];
    4092             :   //
    4093           0 : }
    4094             : //======================================================================================

Generated by: LCOV version 1.11