]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - STEER/AliRelAlignerKalman.cxx
Change the X and Y values stored by the VertexerZ from (0.,0.) which are the
[u/mrichter/AliRoot.git] / STEER / AliRelAlignerKalman.cxx
index d81808f81be90be8ddc5ab65b301d0cf20708930..99d35bb3b5c491edc0fc36d1290038767e8ba6d6 100644 (file)
 #include <TVector3.h>
 #include <TDecompLU.h>
 #include <TArrayI.h>
+#include <TObjArray.h>
 #include <TH1D.h>
 #include <TF1.h>
 
 #include "AliESDtrack.h"
-#include "AliTrackPointArray.h"
-#include "AliGeomManager.h"
-#include "AliTrackFitterKalman.h"
-#include "AliTrackFitterRieman.h"
-#include "AliESDfriendTrack.h"
 #include "AliESDEvent.h"
-#include "AliESDVertex.h"
 #include "AliExternalTrackParam.h"
 
 #include "AliRelAlignerKalman.h"
@@ -92,153 +87,169 @@ ClassImp(AliRelAlignerKalman)
 //______________________________________________________________________________
 AliRelAlignerKalman::AliRelAlignerKalman():
     TObject(),
-    fAlpha(0.),
-    fLocalX(80.),
     fPTrackParamArr1(new AliExternalTrackParam[fgkNTracksPerMeasurement]),
     fPTrackParamArr2(new AliExternalTrackParam[fgkNTracksPerMeasurement]),
     fMagField(0.),
+    fNMeasurementParams(4),
     fPX(new TVectorD( fgkNSystemParams )),
     fPXcov(new TMatrixDSym( fgkNSystemParams )),
-    fPH(new TMatrixD( fgkNMeasurementParams, fgkNSystemParams )),
+    fPH(new TMatrixD( fNMeasurementParams, fgkNSystemParams )),
     fQ(1.e-15),
-    fPMeasurement(new TVectorD( fgkNMeasurementParams )),
-    fPMeasurementCov(new TMatrixDSym( fgkNMeasurementParams )),
+    fPMeasurement(new TVectorD( fNMeasurementParams )),
+    fPMeasurementCov(new TMatrixDSym( fNMeasurementParams )),
+    fPMeasurementPrediction(new TVectorD( fNMeasurementParams )),
     fOutRejSigmas(1.),
-    fDelta(new Double_t[fgkNSystemParams]),
+    fOutRejSigma2Median(5.),
+    fYZOnly(kFALSE),
     fNumericalParanoia(kTRUE),
     fRejectOutliers(kTRUE),
+    fRejectOutliersSigma2Median(kFALSE),
     fRequireMatchInTPC(kFALSE),
     fCuts(kFALSE),
     fMinPointsVol1(3),
     fMinPointsVol2(50),
-    fMinMom(0.),
-    fMaxMom(1.e100),
+    fMinPt(0.),
+    fMaxPt(1.e100),
     fMaxMatchingAngle(0.1),
     fMaxMatchingDistance(10.),  //in cm
     fCorrectionMode(kFALSE),
     fNTracks(0),
     fNUpdates(0),
     fNOutliers(0),
+    fNOutliersSigma2Median(0),
     fNMatchedCosmics(0),
     fNMatchedTPCtracklets(0),
     fNProcessedEvents(0),
     fTrackInBuffer(0),
+    fTimeStamp(0),
+    fRunNumber(0),
+    fNMerges(0),
+    fNMergesFailed(0),
     fTPCvd(2.64),
     fTPCZLengthA(2.4972500e02),
     fTPCZLengthC(2.4969799e02)
 {
   //Default constructor
-
-  //default seed: zero, reset errors to large default
+  for (Int_t i=0;i<fgkNSystemParams;i++) fDelta[i] = 1.e-6;
+  for (Int_t i=0; i<4;i++){fResArrSigma2Median[i]=NULL;}
   Reset();
 }
 
 //______________________________________________________________________________
 AliRelAlignerKalman::AliRelAlignerKalman(const AliRelAlignerKalman& a):
     TObject(static_cast<TObject>(a)),
-    fAlpha(a.fAlpha),
-    fLocalX(a.fLocalX),
     fPTrackParamArr1(new AliExternalTrackParam[fgkNTracksPerMeasurement]),
     fPTrackParamArr2(new AliExternalTrackParam[fgkNTracksPerMeasurement]),
     fMagField(a.fMagField),
+    fNMeasurementParams(a.fNMeasurementParams),
     fPX(new TVectorD( *a.fPX )),
     fPXcov(new TMatrixDSym( *a.fPXcov )),
-    fPH(new TMatrixD( *a.fPH )),
+    fPH(new TMatrixD( fNMeasurementParams, fgkNSystemParams )),
     fQ(a.fQ),
-    fPMeasurement(new TVectorD( *a.fPMeasurement )),
-    fPMeasurementCov(new TMatrixDSym( *a.fPMeasurementCov )),
+    fPMeasurement(new TVectorD( fNMeasurementParams )),
+    fPMeasurementCov(new TMatrixDSym( fNMeasurementParams )),
+    fPMeasurementPrediction(new TVectorD( fNMeasurementParams )),
     fOutRejSigmas(a.fOutRejSigmas),
-    fDelta(new Double_t[fgkNSystemParams]),
+    fOutRejSigma2Median(a.fOutRejSigma2Median),
+    fYZOnly(a.fYZOnly),
     fNumericalParanoia(a.fNumericalParanoia),
     fRejectOutliers(a.fRejectOutliers),
+    fRejectOutliersSigma2Median(a.fRejectOutliersSigma2Median),
     fRequireMatchInTPC(a.fRequireMatchInTPC),
     fCuts(a.fCuts),
     fMinPointsVol1(a.fMinPointsVol1),
     fMinPointsVol2(a.fMinPointsVol2),
-    fMinMom(a.fMinMom),
-    fMaxMom(a.fMaxMom),
+    fMinPt(a.fMinPt),
+    fMaxPt(a.fMaxPt),
     fMaxMatchingAngle(a.fMaxMatchingAngle),
     fMaxMatchingDistance(a.fMaxMatchingDistance),  //in cm
     fCorrectionMode(a.fCorrectionMode),
     fNTracks(a.fNTracks),
     fNUpdates(a.fNUpdates),
     fNOutliers(a.fNOutliers),
+    fNOutliersSigma2Median(a.fNOutliersSigma2Median),
     fNMatchedCosmics(a.fNMatchedCosmics),
     fNMatchedTPCtracklets(a.fNMatchedTPCtracklets),
     fNProcessedEvents(a.fNProcessedEvents),
-    fTrackInBuffer(a.fTrackInBuffer),
+    fTrackInBuffer(0),
+    fTimeStamp(a.fTimeStamp),
+    fRunNumber(a.fRunNumber),
+    fNMerges(a.fNMerges),
+    fNMergesFailed(a.fNMergesFailed),
     fTPCvd(a.fTPCvd),
     fTPCZLengthA(a.fTPCZLengthA),
     fTPCZLengthC(a.fTPCZLengthC)
-    //fApplyCovarianceCorrection(a.fApplyCovarianceCorrection),
-    //fCalibrationMode(a.fCalibrationMode),
-    //fFillHistograms(a.fFillHistograms),
-    //fNHistogramBins(a.fNHistogramBins),
-    //fPMes0Hist(new TH1D(*a.fPMes0Hist)),
-    //fPMes1Hist(new TH1D(*a.fPMes1Hist)),
-    //fPMes2Hist(new TH1D(*a.fPMes2Hist)),
-    //fPMes3Hist(new TH1D(*a.fPMes3Hist)),
-    //fPMesErr0Hist(new TH1D(*a.fPMesErr0Hist)),
-    //fPMesErr1Hist(new TH1D(*a.fPMesErr1Hist)),
-    //fPMesErr2Hist(new TH1D(*a.fPMesErr2Hist)),
-    //fPMesErr3Hist(new TH1D(*a.fPMesErr3Hist)),
-    //fPMeasurementCovCorr(new TMatrixDSym(*a.fPMeasurementCovCorr)),
 {
   //copy constructor
   memcpy(fDelta,a.fDelta,fgkNSystemParams*sizeof(Double_t));
+
+  //copy contents of the residuals array for sigma2median scheme
+  for (Int_t i=0;i<4;i++)
+  {
+    if ((a.fResArrSigma2Median)[i]) 
+    {
+      fResArrSigma2Median[i] = new Double_t[fgkNtracksSigma2Median];
+      memcpy(fResArrSigma2Median[i],(a.fResArrSigma2Median)[i],
+             fgkNtracksSigma2Median*sizeof(Double_t));
+    }
+    else
+      fResArrSigma2Median[i] = NULL;
+  }
 }
 
 //______________________________________________________________________________
 AliRelAlignerKalman& AliRelAlignerKalman::operator=(const AliRelAlignerKalman& a)
 {
   //assignment operator
-  //fAlpha=a.fAlpha;
-  //fLocalX=a.fLocalX;
-  //memcpy(fPTrackParamArr1,a.fPTrackParamArr1,fgkNTracksPerMeasurement*sizeof(AliExternalTrackParam));
-  //memcpy(fPTrackParamArr2,a.fPTrackParamArr2,fgkNTracksPerMeasurement*sizeof(AliExternalTrackParam));
   fMagField=a.fMagField,
+  fNMeasurementParams=a.fNMeasurementParams;
   *fPX = *a.fPX;
   *fPXcov = *a.fPXcov;
-  //*fPH = *a.fPH;
   fQ=a.fQ;
-  //*fPMeasurement=*a.fPMeasurement;
-  //*fPMeasurementCov=*a.fPMeasurementCov;
   fOutRejSigmas=a.fOutRejSigmas;
+  fOutRejSigma2Median=a.fOutRejSigma2Median;
   memcpy(fDelta,a.fDelta,fgkNSystemParams*sizeof(Double_t));
+  fYZOnly=a.fYZOnly;
   fNumericalParanoia=a.fNumericalParanoia;
   fRejectOutliers=a.fRejectOutliers;
+  fRejectOutliersSigma2Median=a.fRejectOutliersSigma2Median;
   fRequireMatchInTPC=a.fRequireMatchInTPC;
   fCuts=a.fCuts;
   fMinPointsVol1=a.fMinPointsVol1;
   fMinPointsVol2=a.fMinPointsVol2;
-  fMinMom=a.fMinMom;
-  fMaxMom=a.fMaxMom;
+  fMinPt=a.fMinPt;
+  fMaxPt=a.fMaxPt;
   fMaxMatchingAngle=a.fMaxMatchingAngle;
   fMaxMatchingDistance=a.fMaxMatchingDistance;  //in c;
   fCorrectionMode=a.fCorrectionMode;
   fNTracks=a.fNTracks;
   fNUpdates=a.fNUpdates;
   fNOutliers=a.fNOutliers;
+  fNOutliersSigma2Median=a.fNOutliersSigma2Median;
   fNMatchedCosmics=a.fNMatchedCosmics;
   fNMatchedTPCtracklets=a.fNMatchedTPCtracklets;
   fNProcessedEvents=a.fNProcessedEvents;
-  fTrackInBuffer=a.fTrackInBuffer;
-  //fApplyCovarianceCorrection=a.fApplyCovarianceCorrection;
-  //fCalibrationMode=a.fCalibrationMode;
-  //fFillHistograms=a.fFillHistograms;
-  //fNHistogramBins=a.fNHistogramBins;
-  //*fPMes0Hist=*(a.fPMes0Hist);
-  //*fPMes1Hist=*(a.fPMes1Hist);
-  //*fPMes2Hist=*(a.fPMes2Hist);
-  //*fPMes3Hist=*(a.fPMes3Hist);
-  //*fPMesErr0Hist=*(a.fPMesErr0Hist);
-  //*fPMesErr1Hist=*(a.fPMesErr1Hist);
-  //*fPMesErr2Hist=*(a.fPMesErr2Hist);
-  //*fPMesErr3Hist=*(a.fPMesErr3Hist);
-  //*fPMeasurementCovCorr=*(a.fPMeasurementCovCorr);
+  fTrackInBuffer=0; //because the array is reset, not copied
+  fTimeStamp=a.fTimeStamp;
+  fRunNumber=a.fRunNumber;
+  fNMerges=a.fNMerges;
   fTPCvd=a.fTPCvd;
   fTPCZLengthA=a.fTPCZLengthA;
   fTPCZLengthC=a.fTPCZLengthC;
+
+  //copy contents of the residuals array for sigma2median scheme
+  for (Int_t i=0;i<4;i++)
+  {
+    if ((a.fResArrSigma2Median)[i]) 
+    {
+      if (!(fResArrSigma2Median[i])) fResArrSigma2Median[i] = 
+                                     new Double_t[fgkNtracksSigma2Median];
+      memcpy(fResArrSigma2Median[i],(a.fResArrSigma2Median)[i],
+             fgkNtracksSigma2Median*sizeof(Double_t));
+    }
+    else
+      fResArrSigma2Median[i] = NULL;
+  }
   return *this;
 }
 
@@ -246,23 +257,17 @@ AliRelAlignerKalman& AliRelAlignerKalman::operator=(const AliRelAlignerKalman& a
 AliRelAlignerKalman::~AliRelAlignerKalman()
 {
   //destructor
-  if (fPTrackParamArr1) delete [] fPTrackParamArr1;
-  if (fPTrackParamArr2) delete [] fPTrackParamArr2;
-  if (fPX) delete fPX;
-  if (fPXcov) delete fPXcov;
-  if (fPH) delete fPH;
-  if (fPMeasurement) delete fPMeasurement;
-  if (fPMeasurementCov) delete fPMeasurementCov;
-  if (fDelta) delete [] fDelta;
-  //if (fPMes0Hist) delete fPMes0Hist;
-  //if (fPMes1Hist) delete fPMes1Hist;
-  //if (fPMes2Hist) delete fPMes2Hist;
-  //if (fPMes3Hist) delete fPMes3Hist;
-  //if (fPMesErr0Hist) delete fPMesErr0Hist;
-  //if (fPMesErr1Hist) delete fPMesErr1Hist;
-  //if (fPMesErr2Hist) delete fPMesErr2Hist;
-  //if (fPMesErr3Hist) delete fPMesErr3Hist;
-  //if (fPMeasurementCovCorr) delete fPMeasurementCovCorr;
+  delete [] fPTrackParamArr1;
+  delete [] fPTrackParamArr2;
+  delete fPX;
+  delete fPXcov;
+  delete fPH;
+  delete fPMeasurement;
+  delete fPMeasurementCov;
+  for (Int_t i=0;i<4;i++) 
+  {
+    delete [] (fResArrSigma2Median[i]);
+  }
 }
 
 //______________________________________________________________________________
@@ -274,47 +279,55 @@ Bool_t AliRelAlignerKalman::AddESDevent( const AliESDEvent* pEvent )
   
   Bool_t success=kFALSE;
   SetMagField( pEvent->GetMagneticField() );
-  AliESDtrack* track;
+  AliESDtrack* track=NULL;
   
   for (Int_t i=0; i<pEvent->GetNumberOfTracks(); i++)
   {
     track = pEvent->GetTrack(i);
     if (!track) continue;
     if ( ((track->GetStatus()&AliESDtrack::kTPCin)>0)&&
-         ((track->GetStatus()&AliESDtrack::kITSout)>0)&&
+         ((track->GetStatus()&AliESDtrack::kITSrefit)>0)&&
          (track->GetNcls(0)>=fMinPointsVol1)&&
          (track->GetNcls(1)>=fMinPointsVol2) )
     { 
       success = ( AddESDtrack( track ) || success );
     }
   }
+  if (success)
+  {
+    fTimeStamp = pEvent->GetTimeStamp();
+    fRunNumber = pEvent->GetRunNumber();
+  }
   return success;
 }
 
 //______________________________________________________________________________
 Bool_t AliRelAlignerKalman::AddESDtrack( const AliESDtrack* pTrack )
 {
-  ////Adds a full track, returns true if results in a new estimate
-
-  //const AliExternalTrackParam* pconstparamsITS = pTrack->GetOuterParam();
-  //if (!pconstparamsITS) return kFALSE;
-  //const AliExternalTrackParam* pconstparamsTPC = pTrack->GetInnerParam();
-  //if (!pconstparamsTPC) return kFALSE;
-  //
-  ////TPC part
-  //AliExternalTrackParam paramsTPC = (*pconstparamsTPC);
-  //paramsTPC.Rotate(pconstparamsITS->GetAlpha());
-  //paramsTPC.PropagateTo(pconstparamsITS->GetX(), pconstparamsITS->GetAlpha());
-
-  //if (!SetTrackParams( pconstparamsITS, &paramsTPC )) return kFALSE;
-  //
-  ////do some accounting and update
-  //return (Update());
-
-  const AliESDtrack* p;
-  p=pTrack; //shuts up the compiler
+  //Adds a full track, returns true if results in a new estimate
+  //  gets the inner TPC parameters from AliESDTrack::GetInnerParam()
+  //  gets the outer ITS parameters from AliESDfriendTrack::GetITSout()
+
+  const AliExternalTrackParam* pconstparamsITS = pTrack->GetOuterParam();
+  if (!pconstparamsITS) return kFALSE;
+  const AliExternalTrackParam* pconstparamsTPC = pTrack->GetInnerParam();
+  if (!pconstparamsTPC) return kFALSE;
   
-  return kFALSE;
+  //TPC part
+  AliExternalTrackParam paramsTPC = (*pconstparamsTPC);
+  paramsTPC.Rotate(pconstparamsITS->GetAlpha());
+  paramsTPC.PropagateTo(pconstparamsITS->GetX(), fMagField);
+
+  return (AddTrackParams(pconstparamsITS, &paramsTPC));
+}
+
+//______________________________________________________________________________
+Bool_t AliRelAlignerKalman::AddTrackParams( const AliExternalTrackParam* p1, const AliExternalTrackParam* p2 )
+{
+  //Update the estimate using new matching tracklets
+
+  if (!SetTrackParams(p1, p2)) return kFALSE;
+  return Update();
 }
 
 //______________________________________________________________________________
@@ -329,7 +342,7 @@ Bool_t AliRelAlignerKalman::AddCosmicEvent( const AliESDEvent* pEvent )
   TArrayI trackTArrTPC(1);
   if (!FindCosmicTrackletNumbersInEvent( trackTArrITS, trackTArrTPC, pEvent )) return kFALSE;
   SetMagField( pEvent->GetMagneticField() );
-  AliESDtrack* ptrack;
+  AliESDtrack* ptrack=NULL;
   const AliExternalTrackParam* pconstparams1;
   const AliExternalTrackParam* pconstparams2;
   AliExternalTrackParam params1;
@@ -350,7 +363,7 @@ Bool_t AliRelAlignerKalman::AddCosmicEvent( const AliESDEvent* pEvent )
     if (!pconstparams2) continue;
     params2 = *pconstparams2; //make copy
     params2.Rotate(params1.GetAlpha());
-    params2.PropagateTo( params1.GetX(), params1.GetAlpha() );
+    params2.PropagateTo( params1.GetX(), fMagField );
 
     if (!SetTrackParams( &params1, &params2 )) continue;
     
@@ -360,9 +373,26 @@ Bool_t AliRelAlignerKalman::AddCosmicEvent( const AliESDEvent* pEvent )
     else
       continue;
   }
+  fTimeStamp=pEvent->GetTimeStamp(); //always update timestamp even when no update performed
+  fRunNumber=pEvent->GetRunNumber();
   return success;
 }
 
+//______________________________________________________________________________
+void AliRelAlignerKalman::SetPoint2Track( Bool_t set )
+{
+  fNMeasurementParams = (set)?2:4;
+  delete fPH;
+  fPH = new TMatrixD( fNMeasurementParams, fgkNSystemParams );
+  delete fPMeasurement;
+  fPMeasurement = new TVectorD( fNMeasurementParams );
+  delete fPMeasurementCov;
+  fPMeasurementCov = new TMatrixDSym( fNMeasurementParams );
+  delete fPMeasurementPrediction;
+  fPMeasurementPrediction = new TVectorD( fNMeasurementParams );
+  fYZOnly = set;
+}
+
 //______________________________________________________________________________
 void AliRelAlignerKalman::Print(Option_t*) const
 {
@@ -370,8 +400,8 @@ void AliRelAlignerKalman::Print(Option_t*) const
   Double_t rad2deg = 180./TMath::Pi();
   printf("\nAliRelAlignerKalman\n");
   if (fCorrectionMode) printf("(Correction mode)\n");
-  printf("  %i pairs, %i updates, %i outliers,\n", fNTracks, fNUpdates, fNOutliers );
-  printf("  %i TPC matches, %i ITS-TPC matches in %i events\n", fNMatchedTPCtracklets, fNMatchedCosmics, fNProcessedEvents );
+  printf("  run: %i, timestamp: %i, magfield: %.3f\n", fRunNumber, fTimeStamp, fMagField);
+  printf("  %i(-%i) inputs, %i(-%i) updates, %i(-%i) merges\n", fNTracks, fNOutliersSigma2Median, fNUpdates, fNOutliers, fNMerges, fNMergesFailed );
   printf("  psi(x):           % .3f ± (%.2f) mrad  |  % .3f ± (%.2f) deg\n",1e3*(*fPX)(0), 1e3*TMath::Sqrt((*fPXcov)(0,0)),(*fPX)(0)*rad2deg,TMath::Sqrt((*fPXcov)(0,0))*rad2deg);
   printf("  theta(y):         % .3f ± (%.2f) mrad  |  % .3f ± (%.2f) deg\n",1e3*(*fPX)(1), 1e3*TMath::Sqrt((*fPXcov)(1,1)),(*fPX)(1)*rad2deg,TMath::Sqrt((*fPXcov)(1,1))*rad2deg);
   printf("  phi(z):           % .3f ± (%.2f) mrad  |  % .3f ± (%.2f) deg\n",1e3*(*fPX)(2), 1e3*TMath::Sqrt((*fPXcov)(2,2)),(*fPX)(2)*rad2deg,TMath::Sqrt((*fPXcov)(2,2))*rad2deg);
@@ -390,7 +420,7 @@ void AliRelAlignerKalman::PrintSystemMatrix()
 {
   //Print the system matrix for this measurement
   printf("Kalman system matrix:\n");
-  for ( Int_t i=0; i<fgkNMeasurementParams; i++ )
+  for ( Int_t i=0; i<fNMeasurementParams; i++ )
   {
     for ( Int_t j=0; j<fgkNSystemParams; j++ )
     {
@@ -406,7 +436,11 @@ void AliRelAlignerKalman::PrintSystemMatrix()
 Bool_t AliRelAlignerKalman::SetTrackParams( const AliExternalTrackParam* exparam1, const AliExternalTrackParam* exparam2 )
 {
   //Set the parameters, exparam1 will normally be ITS and exparam 2 tht TPC
-  
+  fNTracks++; //count added input sets
+
+  //INPUT OUTLIER REJECTION
+  if (fRejectOutliersSigma2Median && IsOutlierSigma2Median(exparam1,exparam2) ) return kFALSE;
+
   fPTrackParamArr1[fTrackInBuffer] = *exparam1;
   fPTrackParamArr2[fTrackInBuffer] = *exparam2;
   
@@ -420,16 +454,6 @@ Bool_t AliRelAlignerKalman::SetTrackParams( const AliExternalTrackParam* exparam
   return kFALSE;
 }
 
-//______________________________________________________________________________
-void AliRelAlignerKalman::SetRefSurface( const Double_t radius, const Double_t alpha )
-{
-  //sets the reference surface by setting the radius (localx)
-  //and rotation angle wrt the global frame of reference
-  //locally the reference surface becomes a plane with x=r;
-  fLocalX = radius;
-  fAlpha = alpha;
-}
-
 //______________________________________________________________________________
 Bool_t AliRelAlignerKalman::Update()
 {
@@ -444,6 +468,7 @@ Bool_t AliRelAlignerKalman::Update()
   //else return UpdateEstimateKalman();
   if (!PrepareMeasurement()) return kFALSE;
   if (!PrepareSystemMatrix()) return kFALSE;
+  if (!PreparePrediction()) return kFALSE;
   return UpdateEstimateKalman();
 }
 
@@ -483,46 +508,51 @@ Bool_t AliRelAlignerKalman::PrepareMeasurement()
     Int_t x = i*4;
     (*fPMeasurement)(x+0) = pararr2[0]-pararr1[0];
     (*fPMeasurement)(x+1) = pararr2[1]-pararr1[1];
-    (*fPMeasurement)(x+2) = pararr2[2]-pararr1[2];
-    (*fPMeasurement)(x+3) = pararr2[3]-pararr1[3];
+    if (!fYZOnly)
+    {
+      (*fPMeasurement)(x+2) = pararr2[2]-pararr1[2];
+      (*fPMeasurement)(x+3) = pararr2[3]-pararr1[3];
+    }
 
     //the covariance
     const Double_t* parcovarr1 = fPTrackParamArr1[i].GetCovariance();
     const Double_t* parcovarr2 = fPTrackParamArr2[i].GetCovariance();
     (*fPMeasurementCov)(x+0,x+0)=parcovarr1[0];
     (*fPMeasurementCov)(x+0,x+1)=parcovarr1[1];
-    (*fPMeasurementCov)(x+0,x+2)=parcovarr1[3];
-    (*fPMeasurementCov)(x+0,x+3)=parcovarr1[6];
     (*fPMeasurementCov)(x+1,x+0)=parcovarr1[1];
     (*fPMeasurementCov)(x+1,x+1)=parcovarr1[2];
-    (*fPMeasurementCov)(x+1,x+2)=parcovarr1[4];
-    (*fPMeasurementCov)(x+1,x+3)=parcovarr1[7];
-    (*fPMeasurementCov)(x+2,x+0)=parcovarr1[3];
-    (*fPMeasurementCov)(x+2,x+1)=parcovarr1[4];
-    (*fPMeasurementCov)(x+2,x+2)=parcovarr1[5];
-    (*fPMeasurementCov)(x+2,x+3)=parcovarr1[8];
-    (*fPMeasurementCov)(x+3,x+0)=parcovarr1[6];
-    (*fPMeasurementCov)(x+3,x+1)=parcovarr1[7];
-    (*fPMeasurementCov)(x+3,x+2)=parcovarr1[8];
-    (*fPMeasurementCov)(x+3,x+3)=parcovarr1[9];
     (*fPMeasurementCov)(x+0,x+0)+=parcovarr2[0];
     (*fPMeasurementCov)(x+0,x+1)+=parcovarr2[1];
-    (*fPMeasurementCov)(x+0,x+2)+=parcovarr2[3];
-    (*fPMeasurementCov)(x+0,x+3)+=parcovarr2[6];
     (*fPMeasurementCov)(x+1,x+0)+=parcovarr2[1];
     (*fPMeasurementCov)(x+1,x+1)+=parcovarr2[2];
-    (*fPMeasurementCov)(x+1,x+2)+=parcovarr2[4];
-    (*fPMeasurementCov)(x+1,x+3)+=parcovarr2[7];
-    (*fPMeasurementCov)(x+2,x+0)+=parcovarr2[3];
-    (*fPMeasurementCov)(x+2,x+1)+=parcovarr2[4];
-    (*fPMeasurementCov)(x+2,x+2)+=parcovarr2[5];
-    (*fPMeasurementCov)(x+2,x+3)+=parcovarr2[8];
-    (*fPMeasurementCov)(x+3,x+0)+=parcovarr2[6];
-    (*fPMeasurementCov)(x+3,x+1)+=parcovarr2[7];
-    (*fPMeasurementCov)(x+3,x+2)+=parcovarr2[8];
-    (*fPMeasurementCov)(x+3,x+3)+=parcovarr2[9];
+    if (!fYZOnly)
+    {
+      (*fPMeasurementCov)(x+0,x+2)=parcovarr1[3];
+      (*fPMeasurementCov)(x+0,x+3)=parcovarr1[6];
+      (*fPMeasurementCov)(x+1,x+2)=parcovarr1[4];
+      (*fPMeasurementCov)(x+1,x+3)=parcovarr1[7];
+      (*fPMeasurementCov)(x+2,x+0)=parcovarr1[3];
+      (*fPMeasurementCov)(x+2,x+1)=parcovarr1[4];
+      (*fPMeasurementCov)(x+2,x+2)=parcovarr1[5];
+      (*fPMeasurementCov)(x+2,x+3)=parcovarr1[8];
+      (*fPMeasurementCov)(x+3,x+0)=parcovarr1[6];
+      (*fPMeasurementCov)(x+3,x+1)=parcovarr1[7];
+      (*fPMeasurementCov)(x+3,x+2)=parcovarr1[8];
+      (*fPMeasurementCov)(x+3,x+3)=parcovarr1[9];
+      (*fPMeasurementCov)(x+0,x+2)+=parcovarr2[3];
+      (*fPMeasurementCov)(x+0,x+3)+=parcovarr2[6];
+      (*fPMeasurementCov)(x+1,x+2)+=parcovarr2[4];
+      (*fPMeasurementCov)(x+1,x+3)+=parcovarr2[7];
+      (*fPMeasurementCov)(x+2,x+0)+=parcovarr2[3];
+      (*fPMeasurementCov)(x+2,x+1)+=parcovarr2[4];
+      (*fPMeasurementCov)(x+2,x+2)+=parcovarr2[5];
+      (*fPMeasurementCov)(x+2,x+3)+=parcovarr2[8];
+      (*fPMeasurementCov)(x+3,x+0)+=parcovarr2[6];
+      (*fPMeasurementCov)(x+3,x+1)+=parcovarr2[7];
+      (*fPMeasurementCov)(x+3,x+2)+=parcovarr2[8];
+      (*fPMeasurementCov)(x+3,x+3)+=parcovarr2[9];
+    }
     
-    fNTracks++; //count added track sets
   }
   //if (fApplyCovarianceCorrection)
   //  *fPMeasurementCov += *fPMeasurementCovCorr;
@@ -535,8 +565,8 @@ Bool_t AliRelAlignerKalman::PrepareSystemMatrix()
   //Calculate the system matrix for the Kalman filter
   //approximate the system using as reference the track in the first volume
 
-  TVectorD z1( fgkNMeasurementParams );
-  TVectorD z2( fgkNMeasurementParams );
+  TVectorD z1( fNMeasurementParams );
+  TVectorD z2( fNMeasurementParams );
   TVectorD x1( fgkNSystemParams );
   TVectorD x2( fgkNSystemParams );
   //get the derivatives
@@ -548,7 +578,7 @@ Bool_t AliRelAlignerKalman::PrepareSystemMatrix()
     x2(i) = x2(i) + fDelta[i]/(2.0);
     if (!PredictMeasurement( z1, x1 )) return kFALSE;
     if (!PredictMeasurement( z2, x2 )) return kFALSE;
-    for (Int_t j=0; j<fgkNMeasurementParams; j++ )
+    for (Int_t j=0; j<fNMeasurementParams; j++ )
     {
       (*fPH)(j,i) = ( z2(j)-z1(j) ) / fDelta[i];
     }
@@ -556,6 +586,13 @@ Bool_t AliRelAlignerKalman::PrepareSystemMatrix()
   return kTRUE;
 }
 
+//______________________________________________________________________________
+Bool_t AliRelAlignerKalman::PreparePrediction()
+{
+  //Prepare the prediction of the measurement using state vector
+  return PredictMeasurement( (*fPMeasurementPrediction), (*fPX) );
+}
+
 //______________________________________________________________________________
 Bool_t AliRelAlignerKalman::PredictMeasurement( TVectorD& pred, const TVectorD& state )
 {
@@ -579,8 +616,11 @@ Bool_t AliRelAlignerKalman::PredictMeasurement( TVectorD& pred, const TVectorD&
       //calculate the predicted residual
       pred(x+0) = oldparam[0] - newparam[0];
       pred(x+1) = oldparam[1] - newparam[1];
-      pred(x+2) = oldparam[2] - newparam[2];
-      pred(x+3) = oldparam[3] - newparam[3];
+      if (!fYZOnly)
+      {
+        pred(x+2) = oldparam[2] - newparam[2];
+        pred(x+3) = oldparam[3] - newparam[3];
+      }
       return kTRUE;
     }
   }
@@ -598,8 +638,11 @@ Bool_t AliRelAlignerKalman::PredictMeasurement( TVectorD& pred, const TVectorD&
       //calculate the predicted residual
       pred(x+0) = newparam[0] - oldparam[0];
       pred(x+1) = newparam[1] - oldparam[1];
-      pred(x+2) = newparam[2] - oldparam[2];
-      pred(x+3) = newparam[3] - oldparam[3];
+      if (!fYZOnly)
+      {
+        pred(x+2) = newparam[2] - oldparam[2];
+        pred(x+3) = newparam[3] - oldparam[3];
+      }
       return kTRUE;
     }
   }
@@ -638,9 +681,9 @@ Bool_t AliRelAlignerKalman::UpdateEstimateKalman()
 //  }
 //  else
 //  {
-    Double_t det;
-    hpht.InvertFast(&det); //since the matrix is small...
-    if (det < 2e-55) return kFALSE; //we need some sort of protection even in this case....
+    Double_t det=0.0;
+    hpht.Invert(&det); //since the matrix is small...
+    if (det < 2e-99) return kFALSE; //we need some sort of protection even in this case....
 //  }
   //printf("KalmanUpdate: det(hpht): %.4g\n",det);
 
@@ -648,14 +691,13 @@ Bool_t AliRelAlignerKalman::UpdateEstimateKalman()
 
   // update the state and its covariance matrix
   TVectorD xupdate(fgkNSystemParams);
-  TVectorD hx(fgkNMeasurementParams);
-  PredictMeasurement( hx, (*fPX) );
-  xupdate = k*((*fPMeasurement)-hx);
+  xupdate = k*((*fPMeasurement)-(*fPMeasurementPrediction));
 
   //SIMPLE OUTLIER REJECTION
   if ( IsOutlier( xupdate, (*fPXcov) ) && fRejectOutliers )
   {
     fNOutliers++;
+    //printf("AliRelAlignerKalman: outlier\n");
     return kFALSE;
   }
 
@@ -687,9 +729,41 @@ Bool_t AliRelAlignerKalman::IsOutlier( const TVectorD& update, const TMatrixDSym
   return is;
 }
 
+//______________________________________________________________________________
+Bool_t AliRelAlignerKalman::IsOutlierSigma2Median( const AliExternalTrackParam* pITS, 
+                                                   const AliExternalTrackParam* pTPC )
+{
+  //check if the input residuals are not too far off their median
+  TVectorD vecDelta(4),vecMedian(4), vecRMS(4);
+  TVectorD vecDeltaN(5);
+  Double_t sign=(pITS->GetParameter()[1]>0)? 1.:-1.;
+  vecDeltaN[4]=0;
+  for (Int_t i=0;i<4;i++){
+    vecDelta[i]=(pITS->GetParameter()[i]-pTPC->GetParameter()[i])*sign;
+    (fResArrSigma2Median[i])[(fNTracks-1)%fgkNtracksSigma2Median]=vecDelta[i];
+  }
+  Int_t entries=(fNTracks<fgkNtracksSigma2Median)?fNTracks:fgkNtracksSigma2Median;
+  for (Int_t i=0;i<fNMeasurementParams;i++){       //in point2trackmode just take the first 2 params (zy)
+    vecMedian[i] = TMath::Median(entries,fResArrSigma2Median[i]);
+    vecRMS[i]    = TMath::RMS(entries,fResArrSigma2Median[i]);
+    vecDeltaN[i] = 0;
+    if (vecRMS[i]>0.){
+      vecDeltaN[i] = (vecDelta[i]-vecMedian[i])/vecRMS[i];
+      vecDeltaN[4]+= TMath::Abs(vecDeltaN[i]);  //sum of abs residuals
+    }
+  }
+  Bool_t outlier=kFALSE;
+  if (fNTracks<3)  outlier=kTRUE;   //median and RMS still to be defined
+  if ( vecDeltaN[4]/fNMeasurementParams>fOutRejSigma2Median) outlier=kTRUE;
+  if (outlier) fNOutliersSigma2Median++;
+  return outlier;
+}
+
 //______________________________________________________________________________
 Bool_t AliRelAlignerKalman::IsPositiveDefinite( const TMatrixD& mat ) const
 {
+  //check for positive definiteness
+
   for (Int_t i=0; i<mat.GetNcols(); i++)
   {
     if (mat(i,i)<=0.) return kFALSE;
@@ -792,7 +866,7 @@ Bool_t AliRelAlignerKalman::FindCosmicTrackletNumbersInEvent( TArrayI& outITSind
     }
     if (fCuts)
     {
-      if (pTrack->GetP()<fMinMom || pTrack->GetP()>fMaxMom) continue;
+      if (pTrack->GetP()<fMinPt || pTrack->GetP()>fMaxPt) continue;
     }
     goodtracksArr[nGoodTracks]=itrack;
     Float_t phi = pTrack->GetAlpha()+TMath::ASin(pTrack->GetSnp());
@@ -1216,7 +1290,11 @@ void AliRelAlignerKalman::Reset()
   ResetCovariance();
 
   //initialize the differentials per parameter
-  for (Int_t i=0;i<fgkNSystemParams;i++) fDelta[i] = 1.e-6;
+  for (Int_t i=0;i<4;i++) 
+  {
+    delete [] (fResArrSigma2Median[i]);
+  }
+  fRejectOutliersSigma2Median=kFALSE;
 
   fNMatchedCosmics=0;
   fNMatchedTPCtracklets=0;
@@ -1224,6 +1302,8 @@ void AliRelAlignerKalman::Reset()
   fNOutliers=0;
   fNTracks=0;
   fNProcessedEvents=0;
+  fRunNumber=0;
+  fTimeStamp=0;
 }
 
 //______________________________________________________________________________
@@ -1269,7 +1349,7 @@ void AliRelAlignerKalman::ResetTPCparamsCovariance( const Double_t number )
   {
     if (fgkNSystemParams>6) (*fPXcov)(6,6) = .1*.1;
     if (fgkNSystemParams>7) (*fPXcov)(7,7) = 1.*1.;
-    if (fgkNSystemParams>8) (*fPXcov)(8,8) = 1.*1.;
+    if (fgkNSystemParams>8) (*fPXcov)(8,8) = .1*.1;
   }
   else
   {
@@ -1291,119 +1371,208 @@ void AliRelAlignerKalman::ResetTPCparamsCovariance( const Double_t number )
 }
 
 //______________________________________________________________________________
-//void AliRelAlignerKalman::PrintCovarianceCorrection()
-//{
-//  //Print the measurement covariance correction matrix
-//  printf("Covariance correction matrix:\n");
-//  for ( Int_t i=0; i<fgkNMeasurementParams; i++ )
-//  {
-//    for ( Int_t j=0; j<i+1; j++ )
-//    {
-//      printf("% -2.2f  ", (*fPMeasurementCovCorr)(i,j) );
-//    }//for i
-//    printf("\n");
-//  }//for j
-//  printf("\n");
-//  return;
-//}
-
-//_______________________________________________________________________________
-//Bool_t AliRelAlignerKalman::UpdateCalibration()
-//{
-//  //Update the calibration with new data (in calibration mode)
-//
-//  fPMes0Hist->Fill( (*fPMeasurement)(0) );
-//  fPMes1Hist->Fill( (*fPMeasurement)(1) );
-//  fPMes2Hist->Fill( (*fPMeasurement)(2) );
-//  fPMes3Hist->Fill( (*fPMeasurement)(3) );
-//  fPMesErr0Hist->Fill( TMath::Sqrt((*fPMeasurementCov)(0,0)) );
-//  fPMesErr1Hist->Fill( TMath::Sqrt((*fPMeasurementCov)(1,1)) );
-//  fPMesErr2Hist->Fill( TMath::Sqrt((*fPMeasurementCov)(2,2)) );
-//  fPMesErr3Hist->Fill( TMath::Sqrt((*fPMeasurementCov)(3,3)) );
-//  return kTRUE;
-//}
+Bool_t AliRelAlignerKalman::Merge( const AliRelAlignerKalman* al )
+{
+  //Merge two aligners
+  
+  if (!al) return kFALSE;
+  if (al==this) return kTRUE;
+  if (al->fNUpdates == 0) return kTRUE; //no point in merging with an empty one
+  
+  //store the pointers to current stuff
+  TVectorD* pmes = fPMeasurement;
+  TMatrixDSym* pmescov = fPMeasurementCov;
+  TVectorD* pmespred = fPMeasurementPrediction;
+  TMatrixD* ph = fPH;
+
+  //make a unity system matrix
+  TMatrixD tmp(fgkNSystemParams,fgkNSystemParams);
+  fPH = new TMatrixD(TMatrixD::kUnit, tmp);
+
+  //mesurement is the state of the new aligner
+  fPMeasurement = al->fPX;
+  fPMeasurementCov = al->fPXcov;
+
+  //the mesurement prediction is the state
+  fPMeasurementPrediction = fPX; //this is safe as fPX doesn't change until end
+  
+  //do the merging
+  Bool_t success = UpdateEstimateKalman();
+  
+  //restore pointers to old stuff
+  fPMeasurement = pmes;
+  fPMeasurementCov = pmescov;
+  fPMeasurementPrediction = pmespred;
+  delete fPH;
+  fPH = ph;
+
+  //merge stats
+  if (!success)    
+  {
+    fNMergesFailed++;
+    //printf("AliRelAlignerKalman::Merge failed\n");
+    return kFALSE; //no point in merging stats if merge not succesful
+  }
+  fNProcessedEvents += al->fNProcessedEvents;
+  fNUpdates += al->fNUpdates;
+  fNOutliers += al->fNOutliers;
+  fNOutliersSigma2Median += al->fNOutliersSigma2Median;
+  fNTracks += al->fNTracks;
+  fNMatchedTPCtracklets += al->fNMatchedTPCtracklets;
+  fNMatchedCosmics += al->fNMatchedCosmics;
+  if (fNMerges==0 || al->fNMerges==0) fNMerges++;
+  else fNMerges += al->fNMerges;
+  if (fTimeStamp < al->fTimeStamp) fTimeStamp = al->fTimeStamp; //take the newer one
+
+  return success;
+}
 
 //______________________________________________________________________________
-//Bool_t AliRelAlignerKalman::SetCalibrationMode( const Bool_t cp )
-//{
-//  //sets the calibration mode
-//  if (cp)
-//  {
-//    fCalibrationMode=kTRUE;
-//    return kTRUE;
-//  }//if (cp)
-//  else
-//  {
-//    if (fCalibrationMode) // do it only after the calibration pass
-//    {
-//      CalculateCovarianceCorrection();
-//      SetApplyCovarianceCorrection();
-//      fCalibrationMode=kFALSE;
-//      return kTRUE;
-//    }//if (fCalibrationMode)
-//  }//else (cp)
-//  return kFALSE;
-//}
+Long64_t AliRelAlignerKalman::Merge( TCollection* list )
+{
+  //merge all aligners in the collection
+  Long64_t numberOfMerges=0;
+  AliRelAlignerKalman* alignerFromList;
+  if (!list) return 0;
+  TIter next(list);
+  while ( (alignerFromList = dynamic_cast<AliRelAlignerKalman*>(next())) )
+  {
+    if (alignerFromList == this) continue;
+    if (Merge(alignerFromList)) numberOfMerges++;
+  }
+  return numberOfMerges;
+}
 
 //______________________________________________________________________________
-//Bool_t AliRelAlignerKalman::CalculateCovarianceCorrection()
-//{
-//  //Calculates the correction to the measurement covariance
-//  //using the calibration histograms
-//
-//  fPMeasurementCovCorr->Zero(); //reset the correction
-//
-//  Double_t s,m,c;  //sigma,meansigma,correction
-//
-//  //TF1* fitformula;
-//  //fPMes0Hist->Fit("gaus");
-//  //fitformula = fPMes0Hist->GetFunction("gaus");
-//  //s = fitformula->GetParameter(2);   //spread of the measurement
-//  //fPMesErr0Hist->Fit("gaus");
-//  //fitformula = fPMesErr0Hist->GetFunction("gaus"); //average error from cov matrices
-//  //m = fitformula->GetParameter(1);
-//  s = fPMes0Hist->GetRMS();
-//  m = fPMesErr0Hist->GetMean();
-//  c = s-m; //the difference between the average error and real spread of the data
-//  if (c>0) //only correct is spread bigger than average error
-//    (*fPMeasurementCovCorr)(0,0) = c*c;
-//
-//  //fPMes1Hist->Fit("gaus");
-//  //fitformula = fPMes1Hist->GetFunction("gaus");
-//  //s = fitformula->GetParameter(2);
-//  //fPMesErr1Hist->Fit("gaus");
-//  //fitformula = fPMesErr1Hist->GetFunction("gaus");
-//  //m = fitformula->GetParameter(1);
-//  s = fPMes1Hist->GetRMS();
-//  m = fPMesErr1Hist->GetMean();
-//  c = s-m;
-//  if (c>0) //only correct is spread bigger than average error
-//    (*fPMeasurementCovCorr)(1,1) = c*c;
-//
-//  //fPMes2Hist->Fit("gaus");
-//  //fitformula = fPMes2Hist->GetFunction("gaus");
-//  //s = fitformula->GetParameter(2);
-//  //fPMesErr2Hist->Fit("gaus");
-//  //fitformula = fPMesErr2Hist->GetFunction("gaus");
-//  //m = fitformula->GetParameter(1);
-//  s = fPMes2Hist->GetRMS();
-//  m = fPMesErr2Hist->GetMean();
-//  c = s-m;
-//  if (c>0) //only correct is spread bigger than average error
-//    (*fPMeasurementCovCorr)(2,2) = c*c;
-//
-//  //fPMes3Hist->Fit("gaus");
-//  //fitformula = fPMes3Hist->GetFunction("gaus");
-//  //s = fitformula->GetParameter(2);
-//  //fPMesErr3Hist->Fit("gaus");
-//  //fitformula = fPMesErr3Hist->GetFunction("gaus");
-//  //m = fitformula->GetParameter(1);
-//  s = fPMes3Hist->GetRMS();
-//  m = fPMesErr3Hist->GetMean();
-//  c = s-m;
-//  if (c>0) //only correct is spread bigger than average error
-//    (*fPMeasurementCovCorr)(3,3) = c*c;
-//
-//  return kTRUE;
-//}
+Int_t AliRelAlignerKalman::Compare(const TObject *obj) const
+{
+  if (this == obj) return 0;
+  const AliRelAlignerKalman* aobj = dynamic_cast<const AliRelAlignerKalman*>(obj);
+  if (!aobj) return 0;
+  if (fTimeStamp < aobj->fTimeStamp) return -1;
+  else if (fTimeStamp > aobj->fTimeStamp) return 1;
+  else return 0;
+}
+
+//________________________________________________________________________
+Int_t AliRelAlignerKalman::FindMatchingTracks(TObjArray& arrITS, TObjArray& arrTPC, AliESDEvent* pESD)
+{
+  //find matching tracks and return tobjarrays with the params
+  
+  Int_t ntracks = pESD->GetNumberOfTracks();
+  Int_t* matchedArr = new Int_t[ntracks]; //storage for index of ITS track for which a match was found
+  for (Int_t i=0;i<ntracks;i++)
+  {
+    matchedArr[i]=0;
+  }
+
+  Int_t iMatched=-1;
+  for (Int_t i=0; i<ntracks; i++)
+  {
+    //get track1 and friend
+    AliESDtrack* track1 = pESD->GetTrack(i);
+    if (!track1) continue;
+
+    if (track1->GetNcls(0) < fMinPointsVol1) continue;
+
+    if (!( ( track1->IsOn(AliESDtrack::kITSrefit)) &&
+           (!track1->IsOn(AliESDtrack::kTPCin)) )) continue;
+
+    const AliESDfriendTrack* constfriendtrack1 = track1->GetFriendTrack();
+    if (!constfriendtrack1) continue;
+    AliESDfriendTrack friendtrack1(*constfriendtrack1);
+    
+    if (!friendtrack1.GetITSOut()) continue;
+    AliExternalTrackParam params1(*(friendtrack1.GetITSOut()));
+
+    Double_t bestd = 1000.; //best distance
+    Bool_t newi = kTRUE; //whether we start with a new i
+    for (Int_t j=0; j<ntracks; j++)
+    {
+      if (matchedArr[j]>0 && matchedArr[j]!=i) continue; //already matched, everything tried 
+      //get track2 and friend
+      AliESDtrack* track2 = pESD->GetTrack(j);
+      if (!track2) continue;
+      if (track1==track2) continue;
+      //if ( ( ( track2->IsOn(AliESDtrack::kITSout)) &&
+      //       (!track2->IsOn(AliESDtrack::kTPCin)) )) continue; //all but ITS standalone
+
+      if (track2->GetNcls(0) != track1->GetNcls(0)) continue;
+      if (track2->GetITSClusterMap() != track1->GetITSClusterMap()) continue;
+      if (track2->GetNcls(1) < fMinPointsVol2) continue; //min 80 clusters in TPC
+      if (track2->GetTgl() > 1.) continue; //acceptance
+      //cut crossing tracks
+      if (track2->GetOuterParam()->GetZ()*track2->GetInnerParam()->GetZ()<0) continue;
+      if (track2->GetInnerParam()->GetX()>90) continue;
+      if (TMath::Abs(track2->GetInnerParam()->GetZ())<10.) continue; //too close to membrane?
+
+
+      if (!track2->GetInnerParam()) continue;
+      AliExternalTrackParam params2(*(track2->GetInnerParam()));
+
+      //bring to same reference plane
+      if (!params2.Rotate(params1.GetAlpha())) continue;
+      if (!params2.PropagateTo(params1.GetX(), pESD->GetMagneticField())) continue;
+
+      //pt cut
+      if (params2.Pt() < fMinPt) continue;
+
+      const Double32_t*        p1 = params1.GetParameter();
+      const Double32_t*        p2 = params2.GetParameter();
+
+      //hard cuts
+      Double_t dy = TMath::Abs(p2[0]-p1[0]);
+      Double_t dz = TMath::Abs(p2[1]-p1[1]);
+      Double_t dphi = TMath::Abs(p2[2]-p1[2]);
+      Double_t dlam = TMath::Abs(p2[3]-p1[3]);
+      if (dy > 2.0) continue;
+      if (dz > 10.0) continue;
+      if (dphi > 0.1 ) continue;
+      if (dlam > 0.1 ) continue;
+
+      //best match only
+      Double_t d = TMath::Sqrt(dy*dy+dz*dz+dphi*dphi+dlam*dlam);
+      if ( d >= bestd) continue;
+      bestd = d;
+      matchedArr[j]=i; //j-th track matches i-th (ITS) track
+      if (newi) iMatched++; newi=kFALSE; //increment at most once per i
+      if (arrITS[iMatched] && arrTPC[iMatched])
+      {
+        *(arrITS[iMatched]) = params1;
+        *(arrTPC[iMatched]) = params2;
+      }
+      else
+      {
+        arrITS[iMatched] = new AliExternalTrackParam(params1);
+        arrTPC[iMatched] = new AliExternalTrackParam(params2);
+      }//else
+    }//for j
+  }//for i
+  return iMatched;
+}
 
+//________________________________________________________________________
+void AliRelAlignerKalman::SetRejectOutliersSigma2Median(const Bool_t set )
+{
+  //Sets up or destroys the memory hungry array to hold the statistics
+  //for data rejection with median
+  if (set)
+  {
+    for (Int_t i=0;i<4;i++) 
+    {
+      if (!fResArrSigma2Median[i]) fResArrSigma2Median[i] = 
+                                   new Double_t[fgkNtracksSigma2Median];
+    }
+    fRejectOutliersSigma2Median = kTRUE;
+  }//else
+  else
+  {
+    // it probably doesn't make sense to delete the arrays, they are not streamed
+    //if (fRejectOutliersSigma2Median)
+    //for (Int_t i=0;i<4;i++) 
+    //{
+    //  delete [] (fResArrSigma2Median[i]);
+    //}
+    fRejectOutliersSigma2Median = kFALSE;
+  }//if
+}