diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..906b53eff120aa483f60fbf1dd2c4501831ff9bb
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __ITRIG_L2_FAST_EXTRAPOLATION_TOOL_H__
+#define __ITRIG_L2_FAST_EXTRAPOLATION_TOOL_H__
+
+#include "GaudiKernel/IAlgTool.h"
+#include <vector>
+
+namespace Trk {
+    class TrkPlanarSurface;
+    class TrkTrackState;
+}
+
+static const InterfaceID IID_ITrigL2FastExtrapolationTool("ITrigL2FastExtrapolationTool",1,0);
+
+
+  /** @class ITrigL2FastExtrapolationTool
+
+      provides the abstract interface for a track extrapolation tool used by TrigInDetTrackFitter
+
+      @author D.Emeliyanov <http://consult.cern.ch/xwho>
+  */
+
+  class ITrigL2FastExtrapolationTool : virtual public IAlgTool {
+
+  public:
+    /** other standard AlgTool methods */
+
+    static const InterfaceID& interfaceID ()   //!< the Tool's interface
+      {  return IID_ITrigL2FastExtrapolationTool; }  	
+    virtual Trk::TrkTrackState* extrapolate(Trk::TrkTrackState*,
+					    Trk::TrkPlanarSurface*,
+					    Trk::TrkPlanarSurface*, bool) = 0;
+  };
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/ITrigL2TrackFittingTool.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/ITrigL2TrackFittingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..01f66862c08149ee01ee666aa4280ae7506cebeb
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/ITrigL2TrackFittingTool.h
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __ITRIG_L2_TRACK_FITTING_TOOL_H__
+#define __ITRIG_L2_TRACK_FITTING_TOOL_H__
+
+#include "GaudiKernel/IAlgTool.h"
+#include <vector>
+
+namespace Trk {
+    class TrkBaseNode;
+    class TrkTrackState;
+}
+
+static const InterfaceID IID_ITrigL2TrackFittingTool("ITrigL2TrackFittingTool",1,0);
+
+
+  /** @class ITrigL2TrackFittingTool
+
+      provides the abstract interface for track fitting tools used by TrigInDetTrackFitter
+
+      @author D.Emeliyanov <http://consult.cern.ch/xwho>
+  */
+
+  class ITrigL2TrackFittingTool : virtual public IAlgTool { 
+
+  public:
+    /** other standard AlgTool methods */
+
+    static const InterfaceID& interfaceID ()   //!< the Tool's interface
+      {  return IID_ITrigL2TrackFittingTool; }  	
+
+    virtual Trk::TrkTrackState* fit(Trk::TrkTrackState*, std::vector<Trk::TrkBaseNode*>&, bool) = 0;
+  };
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/PerigeeFilteringNodes.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/PerigeeFilteringNodes.h
new file mode 100755
index 0000000000000000000000000000000000000000..6a591f6c9031a18c2bf58398f02ab2b11a05083a
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/PerigeeFilteringNodes.h
@@ -0,0 +1,99 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __PERIGEEFILTERINGNODES_H__
+#define __PERIGEEFILTERINGNODES_H__
+
+class TrigSiSpacePoint;
+
+class BasePerigeeFilteringNode
+{
+ public:
+  BasePerigeeFilteringNode();
+  virtual ~BasePerigeeFilteringNode(){};
+  virtual double m_getChi2(double*,double*) = 0;
+  virtual void m_runFilter(double*,double*);
+  virtual void m_applyMultScatt(double*,double*);
+  virtual void m_applyEnergyLoss(double*,double*,int);
+  virtual int m_getNdof() = 0;
+  virtual double m_getRho() = 0;
+  void m_setType(char type)
+    {
+      m_nType=type;
+    }
+  char m_getType()
+    {
+      return m_nType;
+    }
+  void m_setLayer(long lay)
+    {
+      m_nLayer=lay;
+    }
+  long m_getLayer()
+    {
+      return m_nLayer;
+    }
+  const TrigSiSpacePoint* m_getTrigSp()
+    {
+      return m_pTrigSp;
+    }
+  bool m_isAccepted();
+  void m_acceptIt();
+  void m_rejectIt();
+ protected:
+  char m_nType,m_nStatus;
+  long m_nLayer;
+  double m_dChi2;
+  double m_D[2][2];
+  double m_B[2][5];
+  double m_resid[2];
+  double m_EffSigmaMS;
+  double m_EffRadLength;
+  double m_Rho;
+  const TrigSiSpacePoint* m_pTrigSp;
+};
+
+class BarrelPerigeeFilteringNode: public BasePerigeeFilteringNode
+{
+ private:
+  double m_Ri;
+  double m_yPhi,m_sigmaPhi;
+  double m_yZ,m_sigmaZ;
+ public:
+  BarrelPerigeeFilteringNode(const TrigSiSpacePoint*);
+  ~BarrelPerigeeFilteringNode(){};
+  double m_getChi2(double*,double*);
+  void m_runFilter(double*,double*);
+  void m_applyMultScatt(double*,double*);
+  void m_applyEnergyLoss(double*,double*,int);
+  double m_getEffRadLength(double*);
+  int m_getNdof();
+  double m_getRho()
+    {
+      return m_Ri;
+    }  
+};
+
+class DiscPerigeeFilteringNode: public BasePerigeeFilteringNode
+{
+ private:
+  double m_Zi;
+  double m_yPhi,m_sigmaPhi;
+  double m_yR,m_sigmaR;
+ public:
+  DiscPerigeeFilteringNode(const TrigSiSpacePoint*);
+  ~DiscPerigeeFilteringNode(){};
+  double m_getChi2(double*,double*);
+  void m_applyMultScatt(double*,double*);
+  void m_applyEnergyLoss(double*,double*,int);
+  double m_getEffRadLength(double*);
+  void m_runFilter(double*,double*);
+  int m_getNdof();
+  double m_getRho()
+    {
+      return m_Rho;
+    }
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigDkfTrackMakerTool.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigDkfTrackMakerTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..f28e389f24e7a8cf5a91a0196118510dd1ef8719
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigDkfTrackMakerTool.h
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGDKFTRACKMAKERTOOL_H__
+#define __TRIGDKFTRACKMAKERTOOL_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+
+#include "TrigInDetToolInterfaces/ITrigDkfTrackMakerTool.h"
+#include <vector>
+
+#include "InDetIdentifier/SCT_ID.h"
+#include "InDetIdentifier/PixelID.h" 
+#include "InDetReadoutGeometry/PixelDetectorManager.h"
+#include "InDetReadoutGeometry/SCT_DetectorManager.h"
+#include "TrkTrack/Track.h"
+
+
+class AtlasDetectorID;
+class PixelID;
+class SCT_ID;
+
+class TrigDkfTrackMakerTool : virtual public ITrigDkfTrackMakerTool, public AthAlgTool {
+ public:
+      
+  // standard AlgTool methods
+  TrigDkfTrackMakerTool(const std::string&,const std::string&,const IInterface*);
+  virtual ~TrigDkfTrackMakerTool();
+		
+  // standard Athena methods
+  StatusCode initialize();
+  StatusCode finalize();
+
+  bool createDkfTrack(std::vector<const TrigSiSpacePoint*>&, std::vector<Trk::TrkBaseNode*>&, double);
+	bool createDkfTrack(const Trk::Track& track, std::vector<Trk::TrkBaseNode*>& vpTrkNodes, double DChi2);
+
+    
+ private:
+  const PixelID* m_pixelId;
+  const SCT_ID* m_sctId;
+  const AtlasDetectorID* m_idHelper;
+  
+  const InDetDD::PixelDetectorManager* m_pixelManager;
+  const InDetDD::SCT_DetectorManager* m_SCT_Manager;
+
+};
+
+#endif 
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetBremDetectionTool.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetBremDetectionTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..1020510c59a3de60aa9856a9b78c1c0f7baaf90b
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetBremDetectionTool.h
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGINDETBREMDETECTIONTOOL_H__
+#define __TRIGINDETBREMDETECTIONTOOL_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/MsgStream.h"
+
+#include "TrigInDetToolInterfaces/ITrigInDetBremDetectionTool.h"
+#include <vector>
+
+#define MAX_RES_SIZE 100
+#define MAX_INP_SIZE 20
+
+
+class LSMSolution  
+{
+public:
+  void m_report();
+  void m_fixVariable(int);
+  bool m_isOnConstraint(int);
+  double& m_Significance();
+  double& m_Cov(int,int);
+  LSMSolution(int);
+  LSMSolution();
+  virtual ~LSMSolution();
+  double& operator[] (int);
+
+private:
+  int m_fixedVariables[MAX_INP_SIZE];
+  double m_Chi2;
+  double m_C[MAX_INP_SIZE][MAX_INP_SIZE];
+  int m_size;
+  double m_u[MAX_INP_SIZE];
+};
+
+class TrigInDetBremDetectionTool : virtual public ITrigInDetBremDetectionTool, public AthAlgTool {
+ public:
+      
+  // standard AlgTool methods
+  TrigInDetBremDetectionTool(const std::string&,const std::string&,const IInterface*);
+  virtual ~TrigInDetBremDetectionTool();
+		
+  // standard Athena methods
+  StatusCode initialize();
+  StatusCode finalize();
+  virtual void reset(); 
+  virtual bool addNewPoint(Trk::TrkTrackState*,Trk::TrkBaseNode*, Trk::TrkPlanarSurface*, double a[5][5],double);
+  virtual bool solve(int);
+  virtual void modifySurfaces(int);
+  virtual void report(int);
+    
+  private:
+
+    void m_mixSolutions(LSMSolution*, LSMSolution*);
+    bool m_checkFeasibility(LSMSolution*);
+    int m_findBestDirection(double*);
+    bool m_goodGradient(double*);
+    bool m_isZempty();
+    double m_getCriterionValue(LSMSolution*);
+    LSMSolution* m_solveLSM();
+    void m_fixVariables(const int *);
+    void m_precomputeGain();
+    void m_report();
+    void m_getGradient(LSMSolution*,double[]);
+    bool CholeskyDecompositionNxN(double*,int);
+    bool invertMatrixNxN(double*, int);
+    double m_K[MAX_INP_SIZE][MAX_RES_SIZE];
+    double m_W[MAX_INP_SIZE][MAX_INP_SIZE];
+    int m_size;
+    
+    double m_A[MAX_RES_SIZE][MAX_INP_SIZE];
+    double m_MG[5][MAX_INP_SIZE];
+    double m_jX[MAX_INP_SIZE];
+    double m_jY[MAX_INP_SIZE];
+    double m_jZ[MAX_INP_SIZE];
+    double m_S[MAX_RES_SIZE][2];
+    mutable MsgStream  m_log;         //!< msgstream as private member (-> speed)
+    int m_outputLevel; //!< private member to control debug messages
+    double m_totalPath;
+    double m_minDistance;
+    double m_P0;
+    double m_SignificanceCut;
+    int m_lsmSize,m_resSize;
+    std::vector<int> m_resSizes;
+    double m_R[MAX_INP_SIZE];
+    
+    int m_Parray[MAX_INP_SIZE];
+    int m_Zarray[MAX_INP_SIZE];
+    int m_sign;
+    double m_Threshold;
+    LSMSolution* m_pLS;
+    Trk::TrkPlanarSurface* m_surfArray[MAX_INP_SIZE];
+  };
+
+#endif 
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetCombinedTrackFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetCombinedTrackFitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e37a0709f3ad10771cd740ce1cc487493cfda9f
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetCombinedTrackFitter.h
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGINDET_COMBINED_TRACKFITTER_H__
+#define __TRIGINDET_COMBINED_TRACKFITTER_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+#include "TrigInDetToolInterfaces/ITrigDkfTrackMakerTool.h"
+#include "TrigInDetTrackFitter/ITrigL2TrackFittingTool.h"
+
+class TrigInDetCombinedTrackFitter: public AthAlgTool, virtual public ITrigInDetTrackFitter
+{
+ public:
+  TrigInDetCombinedTrackFitter( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigInDetCombinedTrackFitter(){};
+  virtual StatusCode initialize();
+  virtual StatusCode finalize();
+  void fit(TrigInDetTrackCollection*);
+  TrackCollection* fit(const TrackCollection&, const Trk::ParticleHypothesis&) {return nullptr;}
+
+private:
+  bool m_doMultScatt,m_doBremm;
+  double m_momentumThreshold,m_DChi2;
+  ToolHandle<ITrigL2TrackFittingTool> m_highPtFitter;
+  ToolHandle<ITrigL2TrackFittingTool> m_lowPtFitter;
+  //ToolHandle<ITrigL2TrackFittingTool> m_robustFitter;
+
+  ToolHandle<ITrigDkfTrackMakerTool> m_trackMaker;
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetKarimakiFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetKarimakiFitter.h
new file mode 100755
index 0000000000000000000000000000000000000000..9892c0a0a3a2a883f35339a0a26f5c018ffae4d0
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetKarimakiFitter.h
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGINDETKARIMAKIFITTER_H__
+#define __TRIGINDETKARIMAKIFITTER_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+
+#include "InDetIdentifier/SCT_ID.h"
+#include "InDetIdentifier/PixelID.h" 
+
+
+class PixelID;
+class SCT_ID;
+
+
+class TrigInDetKarimakiFitter: public AthAlgTool, virtual public ITrigInDetTrackFitter {
+
+  // Ancillary track structure
+  struct AncillaryTrack {
+    
+    // Prefit info
+    double xm1;
+    double ym1;
+    double cx1;
+    double cy1;
+    double eta;
+    double phi;
+    
+    // Fit RZ info
+    double cotantheta;
+    double ang;
+    double z0;
+    
+    // Fit RPhi info
+    double q;
+    double xc;
+    double yc;
+    double rc;
+    double phic;
+    double k;
+    double delta;
+    double pt;
+    
+    // Fit chi2 info
+    double chi2;
+    double chi2rz;
+    double chi2rp;
+    int    nSP;
+  };
+  
+  
+ public:
+  
+  TrigInDetKarimakiFitter(const std::string&, const std::string&, const IInterface*);
+  virtual ~TrigInDetKarimakiFitter();
+  
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+  void fit(TrigInDetTrackCollection*);
+  TrackCollection* fit(const TrackCollection&, const Trk::ParticleHypothesis&) {return nullptr;}
+
+ private:
+  
+  void circlefitRPhi(TrigInDetTrack*, TrigInDetKarimakiFitter::AncillaryTrack&);
+  void fitRZ(TrigInDetTrack*, TrigInDetKarimakiFitter::AncillaryTrack&);
+  void fitRPhi(TrigInDetTrack*, TrigInDetKarimakiFitter::AncillaryTrack&);
+  
+ private:
+  
+  MsgStream* m_log;
+  const PixelID* m_pixelId;
+  const SCT_ID* m_sctId;
+
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetOfflineTrackFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetOfflineTrackFitter.h
new file mode 100755
index 0000000000000000000000000000000000000000..bd2322ec33a549ce4ffe254d29331da5b929621d
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetOfflineTrackFitter.h
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGINDET_OFFLINETRACKFITTER_H__
+#define __TRIGINDET_OFFLINETRACKFITTER_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "TrkFitterInterfaces/ITrackFitter.h"
+#include "TrkFitterUtils/FitterTypes.h"
+#include "InDetIdentifier/SCT_ID.h"
+#include "InDetIdentifier/PixelID.h" 
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+
+class TrigTimer;
+
+
+class TrigInDetOfflineTrackFitter: public AthAlgTool, virtual public ITrigInDetTrackFitter
+{
+ public:
+  TrigInDetOfflineTrackFitter( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigInDetOfflineTrackFitter(){};
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+  void fit(TrigInDetTrackCollection*);
+  TrackCollection* fit(const TrackCollection&, const Trk::ParticleHypothesis&) {return nullptr;}
+private:
+  const PixelID* m_pixelId;
+  const SCT_ID* m_sctId;
+  double m_DChi2;
+  bool m_doMultScatt,m_doBremm,m_offlineClusters;
+  ToolHandle<Trk::ITrackFitter> m_trackFitter;
+
+#define TRIGOFFLINETRACKFIT_NTIMERS 10
+  TrigTimer* m_timer[TRIGOFFLINETRACKFIT_NTIMERS];
+  bool m_timers;
+
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetPerigeeFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetPerigeeFitter.h
new file mode 100755
index 0000000000000000000000000000000000000000..7826e4d4bfbe09d3a810bd56c7bc96b6eb06199b
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetPerigeeFitter.h
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGINDETPERIGEEFITTER_H__
+#define __TRIGINDETPERIGEEFITTER_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+
+class TrigTimer;
+namespace MagField {	
+	class IMagFieldSvc;
+}
+
+class TrigInDetPerigeeFitter: public AthAlgTool, virtual public ITrigInDetTrackFitter
+{
+ public:
+  TrigInDetPerigeeFitter( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigInDetPerigeeFitter();
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+  void fit(TrigInDetTrackCollection*);
+  TrackCollection* fit(const TrackCollection&, const Trk::ParticleHypothesis&) {return nullptr;}
+private:
+
+  void m_clear();
+
+  double m_DChi2;
+  double m_consb;
+  bool m_straightLineMode; 
+  bool m_doMultScatt;
+  bool m_doBremmCorr;
+  std::string m_bfieldToolName;
+
+  ServiceHandle<MagField::IMagFieldSvc> m_MagFieldSvc;
+
+#define PERIGEEFIT_NTIMERS 8
+  TrigTimer* m_timer[PERIGEEFIT_NTIMERS];
+  bool m_timers;
+
+};
+
+
+
+
+
+
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetSctKFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetSctKFitter.h
new file mode 100755
index 0000000000000000000000000000000000000000..3a64f8a6e2f177a9db851f1eef11cace561de6fa
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetSctKFitter.h
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// filename: TrigInDetSctKFitter.h
+// 
+// authors:   original SctKFitting code
+//               Patrice LEBRUN <lebrun@in2p3.fr>
+//               Sijin QIAN <sijin.qian@cern.ch>
+//               Thorsten HUEHN <huehn@scri.fsu.edu>
+//
+//            idScan version
+//               Nikos Konstantinidis
+//               nk@hep.ucl.ac.uk
+//
+//            migration to Athena
+//               Malte Muller 
+//               mm@hep.ucl.ac.uk
+//
+//	      AlgTool version and migration from IdScan
+//               Dmitry Emeliyanov
+//               D.Emeliyanov@rl.ac.uk	 
+//
+// Description: simple Kalman fitting engine
+// 
+// date: 19/11/2002
+// 
+// -------------------------------
+// ATLAS Collaboration
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef __TRIGINDETSCTKFITTER_H__
+#define __TRIGINDETSCTKFITTER_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+
+class TrigInDetSctKFitter: public AthAlgTool, virtual public ITrigInDetTrackFitter   
+{
+ public:
+  void fit(TrigInDetTrackCollection* recoTracks );
+  TrackCollection* fit(const TrackCollection&, const Trk::ParticleHypothesis&) {return nullptr;}
+  TrigInDetSctKFitter( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigInDetSctKFitter();
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+  
+ private:  
+
+  bool m_doBremmCorr;
+  bool m_doMultScatt;
+  double m_DChi2;
+
+  /////////////////////////////////
+  // mostly FORTRAN migrated code
+  /////////////////////////////////
+  
+  // parameters
+  long paramset;
+  double minTrackRadius[4];
+  double maxDChi2[4];
+  
+  void cyl_prg_convertor( double *pari, double *covi, double *r__, 
+			  double *xb, double *yb, 
+			  double *par, double *cov, long *ierr );
+  
+  void matrix_inverter( double *wgt, double *cov, long *ierr );
+  void tkffit( long *np, double *rcoord, double *phcoord, double *zcoord, 
+	       double *errxy, double *errz, double *errr, long *ihtype, double *rf,
+	       double *paraf, double *em1, double *chi2, long *ihdrop, long *ierr,
+	       bool electron );
+  void tfit3p(double *rco, double *fco, double *zco, double *sigxy, 
+	      double *sigz, double *sigr, double *r3, double *para, 
+	      double *wgc, double *chi2c, long *ierr);
+  void tvtoxx(double *pari, double *wctr, double *par, double *wf);		
+  void txprcw(double *wgi, double *der, double *wgf);
+  void txprpw(double *wgi, double *der, double *wgf);
+  void txxdcy(double *p2, double *p1, double *der);
+  void txxdpl(double *p2, double *p1, double *der);
+  void tswtch(long *iz,  double *p1, double *wm1);
+
+  void txtrpa(double *parami, long *idir, double *radf,
+	      double *zmin, double *zmax, double *sinbmx, 
+	      long *iopt, double *paramf, double *der, 
+	      double *alrphi, long *ierr);
+  
+  void txxpla(double *parami, long *idir, double *zf, double *rmin, 
+	      double *rmax, long *iopt, double *paramf, 
+	      double *der, double *alrphi, long *ierr);
+  
+  void tmscat(double *sinth, double *pinv, double *xrl, double *wg, 
+	      double *dir);
+  
+  void add_E_loss(double *x0, double *dir, double *par6, double *wg);
+  
+  void trf2xy(long *idir, double *r, double *phi, double *wm) const;
+  
+  void taddpt(double *df, double *dz,   double *wff,   double *wzz, 
+	      double *dp, double *wotr, double *achi2, long *ierr);
+  
+  void tsolve(double *w, double *vy, double *vz, double *d, long *ier);
+};
+
+#endif
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetTrackFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetTrackFitter.h
new file mode 100755
index 0000000000000000000000000000000000000000..0051067bf9d52def43803a119b4d42f61f1f8838
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigInDetTrackFitter.h
@@ -0,0 +1,75 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGINDETTRACKFITTER_H__
+#define __TRIGINDETTRACKFITTER_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "MagFieldInterfaces/IMagFieldSvc.h" 
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+#include "TrigInDetToolInterfaces/ITrigDkfTrackMakerTool.h"
+
+class TrigTimer;
+
+namespace Trk {	
+  class TrkBaseNode;             
+  class TrkTrackState;      
+  class TrkPlanarSurface;
+}
+
+namespace MagField {	
+	class IMagFieldSvc;
+}
+
+struct FitStatStruct {
+  FitStatStruct(int id) : m_algorithmId(id)  {
+    m_nTracksTotal = 0;
+    for(int i=0;i<5;i++) m_fitErrors[i]=0;
+  }
+  int m_algorithmId;
+  long int m_nTracksTotal;
+  long int m_fitErrors[5];
+};
+
+class TrigInDetTrackFitter: public AthAlgTool, virtual public ITrigInDetTrackFitter
+{
+ public:
+  TrigInDetTrackFitter( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigInDetTrackFitter(){};
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+  void fitTrack(TrigInDetTrack&);
+  void fit(TrigInDetTrackCollection*);
+  Trk::Track* fitTrack(const Trk::Track&, const Trk::ParticleHypothesis& matEffects = Trk::pion);
+  TrackCollection* fit(const TrackCollection&, const Trk::ParticleHypothesis& matEffects = Trk::pion);
+private:
+
+  Trk::TrkTrackState* m_extrapolate(Trk::TrkTrackState*, 
+				    Trk::TrkPlanarSurface*,
+				    Trk::TrkPlanarSurface*);
+  void m_matrixInversion5x5(double a[5][5]);
+  void m_getMagneticField(double[3],double*);
+
+  void correctScale(Trk::TrkTrackState*);
+
+  double m_DChi2;
+  bool m_doMultScatt;
+  bool m_doBremm;
+  bool m_offlineClusters;
+  ServiceHandle<MagField::IMagFieldSvc> m_MagFieldSvc;  
+  ToolHandle<ITrigDkfTrackMakerTool> m_trackMaker;
+
+  std::vector<FitStatStruct> m_fitStats;
+  int m_algorithmId;
+
+#define TRIGTRACKFIT_NTIMERS 10
+  TrigTimer* m_timer[TRIGTRACKFIT_NTIMERS];
+  bool m_timers;
+
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2FastExtrapolationTool.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2FastExtrapolationTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..01d82d686e6ac3773d3097faebb60dd5e72c87be
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2FastExtrapolationTool.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIG_L2_FAST_EXTRAPOLATION_TOOL_H__
+#define __TRIG_L2_FAST_EXTRAPOLATION_TOOL_H__
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h"
+
+namespace Trk {	
+  class TrkTrackState;      
+  class TrkPlanarSurface;
+}
+namespace MagField {	
+	class IMagFieldSvc;
+}
+
+class TrigL2FastExtrapolationTool: public AthAlgTool, virtual public ITrigL2FastExtrapolationTool
+{
+ public:
+  TrigL2FastExtrapolationTool( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigL2FastExtrapolationTool(){};
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+  Trk::TrkTrackState* extrapolate(Trk::TrkTrackState*, 
+				  Trk::TrkPlanarSurface*,
+				  Trk::TrkPlanarSurface*, bool smooth=false);
+private:
+  void m_matrixInversion5x5(double a[5][5]);
+  void m_getMagneticField(double[3],double*);
+  ServiceHandle<MagField::IMagFieldSvc> m_MagFieldSvc;
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2HighPtTrackFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2HighPtTrackFitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ed6b5525c1fbcdba3690b26bc1b17398705de6a
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2HighPtTrackFitter.h
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIG_L2_HIGH_PT_TRACK_FITTER_H__
+#define __TRIG_L2_HIGH_PT_TRACK_FITTER_H__ 
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/ToolHandle.h"
+
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h"
+#include "TrigInDetTrackFitter/ITrigL2TrackFittingTool.h"
+#include "TrkToolInterfaces/IRIO_OnTrackCreator.h"
+#include <vector>
+
+namespace Trk {	
+  class IRIO_OnTrackCreator;
+}
+
+class TrigL2HighPtTrackFitter : virtual public ITrigL2TrackFittingTool, public AthAlgTool {
+ public:
+      
+  // standard AlgTool methods
+  TrigL2HighPtTrackFitter(const std::string&,const std::string&,const IInterface*);
+  virtual ~TrigL2HighPtTrackFitter(){};
+		
+  // standard Athena methods
+  StatusCode initialize();
+  StatusCode finalize();
+  Trk::TrkTrackState* fit(Trk::TrkTrackState*, std::vector<Trk::TrkBaseNode*>&, bool runSmoother=true);
+
+ private:
+
+  void m_recalibrateFilteringNode(Trk::TrkBaseNode*, Trk::TrkTrackState*);
+
+  bool m_recalibrate;
+
+  ToolHandle<ITrigL2FastExtrapolationTool> m_fastExtrapolator;
+  ToolHandle<Trk::IRIO_OnTrackCreator>       m_ROTcreator;
+};
+
+#endif 
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2LowPtTrackFitter.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2LowPtTrackFitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..c00d4edd97c7a3eb4380d355a900cd594e6052f5
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2LowPtTrackFitter.h
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIG_L2_LOW_PT_TRACK_FITTER_H__
+#define __TRIG_L2_LOW_PT_TRACK_FITTER_H__ 
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/ToolHandle.h"
+
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h"
+#include "TrigInDetTrackFitter/ITrigL2TrackFittingTool.h"
+#include "TrkToolInterfaces/IRIO_OnTrackCreator.h"
+#include "TrkExInterfaces/IExtrapolator.h"
+#include <vector>
+
+namespace Trk {	
+  class TrkPlanarSurface;
+  class IRIO_OnTrackCreator;
+  class IExtrapolator;
+}
+
+
+class TrigL2LowPtTrackFitter : virtual public ITrigL2TrackFittingTool, public AthAlgTool {
+ public:
+      
+  // standard AlgTool methods
+  TrigL2LowPtTrackFitter(const std::string&,const std::string&,const IInterface*);
+  virtual ~TrigL2LowPtTrackFitter(){};
+		
+  // standard Athena methods
+  StatusCode initialize();
+  StatusCode finalize();
+  Trk::TrkTrackState* fit(Trk::TrkTrackState*, std::vector<Trk::TrkBaseNode*>&, bool runSmoother=true);
+
+ private:
+
+  Trk::TrkTrackState* m_extrapolateOffline(Trk::TrkTrackState*, 
+					   Trk::TrkPlanarSurface*,
+					   Trk::TrkPlanarSurface*,int);
+
+  void m_recalibrateFilteringNode(Trk::TrkBaseNode*, Trk::TrkTrackState*);
+
+  bool m_recalibrate;
+
+  ToolHandle<ITrigL2FastExtrapolationTool> m_fastExtrapolator;
+  ToolHandle<Trk::IRIO_OnTrackCreator>       m_ROTcreator;
+  ToolHandle<Trk::IExtrapolator> m_extrapolator;
+};
+
+#endif 
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2ResidualCalculator.h b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2ResidualCalculator.h
new file mode 100644
index 0000000000000000000000000000000000000000..64954ba1498b8ddf7e305286b80cea957bba2326
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/TrigInDetTrackFitter/TrigL2ResidualCalculator.h
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __TRIGL2RESIDUALCALCULATOR_H__
+#define __TRIGL2RESIDUALCALCULATOR_H__ 
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "TrigInDetToolInterfaces/ITrigL2ResidualCalculator.h"
+#include "TrigInDetToolInterfaces/ITrigDkfTrackMakerTool.h"
+
+class AtlasDetectorID;
+class PixelID;
+class SCT_ID;
+class TrigL2HitResidual;
+
+namespace Trk {	
+  class TrkBaseNode;             
+  class TrkTrackState;      
+  class TrkPlanarSurface;
+}
+
+namespace MagField {	
+	class IMagFieldSvc;
+}
+
+class TrigL2ResidualCalculator: public AthAlgTool, virtual public ITrigL2ResidualCalculator
+{
+ public:
+
+  TrigL2ResidualCalculator( const std::string&, const std::string&, const IInterface* );
+  virtual ~TrigL2ResidualCalculator(){};
+  virtual StatusCode initialize();
+  virtual StatusCode finalize  ();
+
+  StatusCode getResiduals(const TrigInDetTrack*, std::vector<TrigL2HitResidual>&);
+  StatusCode getUnbiassedResiduals(const TrigInDetTrack*, std::vector<TrigL2HitResidual>&);
+
+private:
+
+  Trk::TrkTrackState* m_extrapolate(Trk::TrkTrackState*, 
+				    Trk::TrkPlanarSurface*,
+				    Trk::TrkPlanarSurface*);
+  void m_matrixInversion5x5(double a[5][5]);
+  void m_getMagneticField(double[3],double*);
+
+  double m_DChi2;
+  bool m_doMultScatt;
+  bool m_doBremm;
+  bool m_offlineClusters;
+  ServiceHandle<MagField::IMagFieldSvc> m_MagFieldSvc;
+  ToolHandle<ITrigDkfTrackMakerTool> m_trackMaker;
+  const PixelID* m_pixelId;
+  const SCT_ID* m_sctId;
+  const AtlasDetectorID* m_idHelper;
+};
+
+#endif
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/cmt/requirements b/Trigger/TrigTools/TrigInDetTrackFitter/cmt/requirements
new file mode 100755
index 0000000000000000000000000000000000000000..769e8a679587c3b300d1148ea187dc22aa9471a3
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/cmt/requirements
@@ -0,0 +1,44 @@
+package TrigInDetTrackFitter
+
+author Dmitry Emeliyanov <D.Emeliyanov@rl.ac.uk>
+
+public
+
+# General
+use TrkTrack                    TrkTrack-*              Tracking/TrkEvent
+use AtlasPolicy			AtlasPolicy-*
+use GaudiInterface		GaudiInterface-*             External
+use InDetIdentifier             InDetIdentifier-*            InnerDetector/InDetDetDescr
+use InDetReadoutGeometry	InDetReadoutGeometry-*	     InnerDetector/InDetDetDescr
+use TrigInDetEvent		TrigInDetEvent-*	     Trigger/TrigEvent
+use TrkDistributedKalmanFilter  TrkDistributedKalmanFilter-* Tracking/TrkFitter
+use TrigInDetToolInterfaces     TrigInDetToolInterfaces-*    Trigger/TrigTools
+use TrkFitterUtils              TrkFitterUtils-*             Tracking/TrkFitter
+use TrkFitterInterfaces         TrkFitterInterfaces-*        Tracking/TrkFitter
+use TrkToolInterfaces           TrkToolInterfaces-*          Tracking/TrkTools
+use TrkExInterfaces             TrkExInterfaces-*            Tracking/TrkExtrapolation
+use MagFieldInterfaces  MagFieldInterfaces-*         MagneticField 
+use AthenaBaseComps							AthenaBaseComps-*				Control
+
+library TrigInDetTrackFitter "*.cxx components/*.cxx"
+    
+apply_pattern component_library
+apply_pattern declare_joboptions files="*.py"
+apply_pattern declare_python_modules files="*.py"
+#apply_pattern declare_non_standard_include name=doc
+
+private
+
+use StoreGate			StoreGate-*		Control
+use AtlasDetDescr               AtlasDetDescr-*         DetectorDescription
+
+use InDetPrepRawData 		InDetPrepRawData-* 	InnerDetector/InDetRecEvent
+use InDetRIO_OnTrack    InDetRIO_OnTrack-*	InnerDetector/InDetRecEvent 
+use TrigTimeAlgs		TrigTimeAlgs-*		Trigger/TrigTools
+
+use TrkSurfaces 		TrkSurfaces-* 	        Tracking/TrkDetDescr
+use TrkParameters	        TrkParameters-* 	Tracking/TrkEvent
+use TrkPrepRawData              TrkPrepRawData-*        Tracking/TrkEvent
+use TrkTrack                    TrkTrack-*              Tracking/TrkEvent
+use TrkEventPrimitives          TrkEventPrimitives-*    Tracking/TrkEvent
+use TrkRIO_OnTrack              TrkRIO_OnTrack-*        Tracking/TrkEvent 
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/doc/mainpage.h b/Trigger/TrigTools/TrigInDetTrackFitter/doc/mainpage.h
new file mode 100755
index 0000000000000000000000000000000000000000..5d57eb7fb57178cce10d857e70e84b6e50f7b7c6
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/doc/mainpage.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+
+@mainpage TrigInDetTrackFitter Package
+
+This package contains implementations of various track fitting tools for the LVL ID 
+tracking. All these tools are based on the same abstract interface: ITrigInDetTrackFitter.  
+
+@author Dmitry.Emeliyanov@cern.ch
+
+@section TrigInDetTrackFitIntro Introduction
+
+The list of track fitting tools is below:
+
+   - TrigInDetTrackFitter - a default track fitter for TrigIDSCAN
+   - TrigInDetPerigeeFitter - a fast fitter which estimates only track perigee parameters and 
+uses TrigSiSpacePoints directly, i.e. without dissolving them into clusters. 
+   - TrigInDetKarimakiFitter - a track fitter for TrigSiTrack
+   - TrigInDetSctKFitter - an old fitter based on Sijin QIAN's code
+
+@section TrigInDetTrackFitOverview Overview
+
+The fitting tools make use of the following abstract interface 
+
+   - ITrigInDetTrackFitter
+
+This interface contains method 
+
+void fit(TrigInDetTrackCollection* recoTracks )
+
+where recoTracks is a collection (vector) of TrigInDetTrack tracks. A track fitter updates parameters 
+of the input tracks so that no new tracks are created. 
+
+*/  
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/python/TrigInDetTrackFitter_Config.py b/Trigger/TrigTools/TrigInDetTrackFitter/python/TrigInDetTrackFitter_Config.py
new file mode 100644
index 0000000000000000000000000000000000000000..dde499bd11adbcb1b306248fe83869c25585775e
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/python/TrigInDetTrackFitter_Config.py
@@ -0,0 +1,133 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from TrigInDetTrackFitter.TrigInDetTrackFitterConf import TrigInDetCombinedTrackFitter
+from TrigInDetTrackFitter.TrigInDetTrackFitterConf import TrigL2HighPtTrackFitter
+from TrigInDetTrackFitter.TrigInDetTrackFitterConf import TrigL2LowPtTrackFitter
+from InDetTrigRecExample.InDetTrigFlags import InDetTrigFlags
+
+
+from TrkExTools.TrkExToolsConf import Trk__Extrapolator
+
+class ConfiguredTrigL2_Extrapolator(Trk__Extrapolator) :
+    __slots__ = []
+    def __init__(self, name = 'ConfiguredTrigL2_Extrapolator') :
+        Trk__Extrapolator.__init__(self, name)
+        from AthenaCommon.AppMgr import ToolSvc
+        from TrkDetDescrSvc.AtlasTrackingGeometrySvc import AtlasTrackingGeometrySvc
+
+        from IOVDbSvc.CondDB import conddb
+        if not (conddb.folderRequested( "/Indet/TrkErrorScaling" ) or conddb.folderRequested( "/Indet/Onl/TrkErrorScaling" )):
+            conddb.addFolderSplitOnline("INDET", "/Indet/Onl/TrkErrorScaling", "/Indet/TrkErrorScaling" )
+        
+        from TrkExSTEP_Propagator.TrkExSTEP_PropagatorConf import Trk__STEP_Propagator
+        TrigL2_StepPropagator = Trk__STEP_Propagator(name = 'TrigL2_StepPropagator')
+        ToolSvc += TrigL2_StepPropagator
+        from TrkExRungeKuttaPropagator.TrkExRungeKuttaPropagatorConf import Trk__RungeKuttaPropagator
+        TrigL2_RKPropagator = Trk__RungeKuttaPropagator(name = 'TrigL2_RKPropagator')
+        ToolSvc += TrigL2_RKPropagator
+        from InDetTrigRecExample.InDetTrigFlags import InDetTrigFlags
+        if InDetTrigFlags.propagatorType() is "STEP":
+            TrigL2_Propagator = TrigL2_StepPropagator
+        else:
+            TrigL2_Propagator = TrigL2_RKPropagator
+        
+        from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+        AtlasTrackingGeometrySvc  = svcMgr.AtlasTrackingGeometrySvc
+        from TrkExTools.TrkExToolsConf import Trk__Navigator
+        TrigL2_Navigator = Trk__Navigator(name = 'TrigL2_Navigator',TrackingGeometrySvc = AtlasTrackingGeometrySvc)
+        ToolSvc += TrigL2_Navigator
+        from TrkExTools.TrkExToolsConf import Trk__MaterialEffectsUpdator
+        TrigL2_MaterialUpdator = Trk__MaterialEffectsUpdator(name = "TrigL2_MaterialEffectsUpdator")
+        ToolSvc += TrigL2_MaterialUpdator
+        TrigL2_SubPropagators = []
+        TrigL2_SubUpdators = []
+        TrigL2_SubPropagators += [ TrigL2_Propagator.name() ]
+        TrigL2_SubUpdators    += [ TrigL2_MaterialUpdator.name() ]
+        TrigL2_SubPropagators += [ TrigL2_Propagator.name() ]
+        TrigL2_SubUpdators    += [ TrigL2_MaterialUpdator.name() ]
+        TrigL2_SubPropagators += [ TrigL2_StepPropagator.name() ]
+        TrigL2_SubUpdators    += [ TrigL2_MaterialUpdator.name() ]
+        self.Propagators             = [ TrigL2_RKPropagator, TrigL2_StepPropagator]
+        self.MaterialEffectsUpdators = [ TrigL2_MaterialUpdator ]
+        self.Navigator               = TrigL2_Navigator
+        self.SubPropagators          = TrigL2_SubPropagators
+        self.SubMEUpdators           = TrigL2_SubUpdators
+        #self.DoCaloDynamic           = False #Obsolete
+
+
+
+
+from TrkRIO_OnTrackCreator.TrkRIO_OnTrackCreatorConf import Trk__RIO_OnTrackCreator
+
+class ConfiguredTrigL2_InDetRotCreator(Trk__RIO_OnTrackCreator) :
+    __slots__ = []
+    def __init__(self, name = 'ConfiguredTrigL2_InDetRotCreator') :
+        Trk__RIO_OnTrackCreator.__init__(self,name)
+        from SiClusterOnTrackTool.SiClusterOnTrackToolConf import InDet__SCT_ClusterOnTrackTool
+        from SiClusterOnTrackTool.SiClusterOnTrackToolConf import InDet__PixelClusterOnTrackTool
+        from InDetTrigRecExample.InDetTrigConditionsAccess import PixelConditionsSetup
+        from InDetTrigRecExample.InDetTrigFlags import InDetTrigFlags
+        
+        if InDetTrigFlags.doCommissioning() :
+            myL2_SCT_ClusterOnTrackTool = InDet__SCT_ClusterOnTrackTool("TrigL2_SCT_ClusterOnTrackTool",
+                                                                        CorrectionStrategy = 0,
+                                                                        ErrorStrategy      = 0)
+            myL2_PixelClusterOnTrackTool = InDet__PixelClusterOnTrackTool("TrigL2_PixelClusterOnTrackTool",
+                                                                          PixelOfflineCalibSvc=PixelConditionsSetup.instanceName('PixelOfflineCalibSvc'),
+                                                                          ErrorStrategy = 0)
+        else:
+            myL2_SCT_ClusterOnTrackTool = InDet__SCT_ClusterOnTrackTool("TrigL2_SCT_ClusterOnTrackTool",CorrectionStrategy = 0,ErrorStrategy      = 2)
+            myL2_PixelClusterOnTrackTool = InDet__PixelClusterOnTrackTool("TrigL2_PixelClusterOnTrackTool",PixelOfflineCalibSvc=PixelConditionsSetup.instanceName('PixelOfflineCalibSvc'),ErrorStrategy = 1)
+                    
+        from AthenaCommon.AppMgr import ToolSvc
+        ToolSvc += myL2_PixelClusterOnTrackTool
+        ToolSvc += myL2_SCT_ClusterOnTrackTool        
+        self.Mode='indet'
+        self.ToolPixelCluster = myL2_PixelClusterOnTrackTool
+        self.ToolSCT_Cluster = myL2_SCT_ClusterOnTrackTool
+
+
+
+
+class ConfiguredTrigL2LowPtTrackFitter(TrigL2LowPtTrackFitter) :
+    __slots__ = []
+    def __init__(self, name = 'ConfiguredTrigL2LowPtTrackFitter') :
+        TrigL2LowPtTrackFitter.__init__(self,name)
+        from AthenaCommon.AppMgr import ToolSvc
+        offlineExtrapolator = ConfiguredTrigL2_Extrapolator()
+        ToolSvc += offlineExtrapolator
+        offlineRotCreator = ConfiguredTrigL2_InDetRotCreator()
+        ToolSvc += offlineRotCreator
+        self.useROTs=False
+        self.ROTcreator=offlineRotCreator
+        self.TrackExtrapolatorTool=offlineExtrapolator
+
+
+        
+
+class ConfiguredTrigL2_TrackFitter(TrigInDetCombinedTrackFitter) :
+    __slots__ = []
+    def __init__(self, name = "ConfiguredTrigL2_TrackFitter") :
+        TrigInDetCombinedTrackFitter.__init__(self, name)
+        from AthenaCommon.AppMgr import ToolSvc
+                
+        offlineRotCreator = ConfiguredTrigL2_InDetRotCreator()
+        ToolSvc += offlineRotCreator
+
+        trigL2HighPtTrackFitter = TrigL2HighPtTrackFitter(name='TrigL2HighPtTrackFitter',
+                                                                    useROTs=False,
+                                                                    ROTcreator=offlineRotCreator)
+        trigL2LowPtTrackFitter = ConfiguredTrigL2LowPtTrackFitter()
+        
+        ToolSvc += trigL2HighPtTrackFitter
+        ToolSvc += trigL2LowPtTrackFitter
+        
+        self.HighPtTrackFitter = trigL2HighPtTrackFitter
+        self.LowPtTrackFitter = trigL2LowPtTrackFitter
+
+
+
+
+
+
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/share/jobOfragment_TrigInDetTrackFitter.py b/Trigger/TrigTools/TrigInDetTrackFitter/share/jobOfragment_TrigInDetTrackFitter.py
new file mode 100755
index 0000000000000000000000000000000000000000..fd799421b07ee0b7504312c9ef15fe985bcdba8b
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/share/jobOfragment_TrigInDetTrackFitter.py
@@ -0,0 +1,16 @@
+theApp.Dlls  += ['TrkDistributedKalmanFilter']
+theApp.Dlls += [ "TrigInDetTrackFitter" ]
+ToolSvc      = Service( "ToolSvc" )
+TrigInDetFitter = Algorithm( 'ToolSvc.TrigInDetTrackFitter' )
+TrigInDetFitter.UseAthenaFieldService=TRUE
+TrigInDetFitter.doMultScattering=TRUE
+TrigInDetFitter.Chi2Cut=100.0
+TrigInDetFitter.OfflineClusters=TriggerFlags.useOfflineSpacePoints
+TrigInDetPerigeeFitter = Algorithm( 'ToolSvc.TrigInDetPerigeeFitter' )
+TrigInDetPerigeeFitter.UseAthenaFieldService=TRUE
+TrigInDetPerigeeFitter.doMultScattering=TRUE
+TrigInDetPerigeeFitter.doBremmCorrection=FALSE
+TrigInDetPerigeeFitter.StraightLineMode=FALSE
+SctKFitter = Algorithm( 'ToolSvc.TrigInDetSctKFitter' )
+SctKFitter.doMultScattering=TRUE
+SctKFitter.doBremmCorrection=FALSE
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/PerigeeFilteringNodes.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/PerigeeFilteringNodes.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..7524c5e62a84ef5675af8f7fce2fe25b41d59d2e
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/PerigeeFilteringNodes.cxx
@@ -0,0 +1,323 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetTrackFitter/PerigeeFilteringNodes.h"
+
+BarrelPerigeeFilteringNode::BarrelPerigeeFilteringNode(const TrigSiSpacePoint* psp)
+{
+  m_Ri=(*psp).r();
+  m_yPhi=(*psp).phi();
+  m_yZ=(*psp).z();
+  m_sigmaPhi=(*psp).dphi();
+  m_sigmaZ=(*psp).dz();
+  m_setType(0);
+  m_pTrigSp=psp;
+  m_acceptIt();
+}
+
+DiscPerigeeFilteringNode::DiscPerigeeFilteringNode(const TrigSiSpacePoint* psp)
+{
+  m_Zi=(*psp).z();
+  m_yPhi=(*psp).phi();
+  m_yR=(*psp).r();
+  m_sigmaPhi=(*psp).dphi();
+  m_sigmaR=(*psp).dr();
+  m_setType(1);
+  m_pTrigSp=psp;
+  m_acceptIt();
+}
+
+BasePerigeeFilteringNode::BasePerigeeFilteringNode()
+{
+  m_nStatus=1; m_pTrigSp=NULL;
+}
+
+void BasePerigeeFilteringNode::m_rejectIt()
+{
+  m_nStatus=0;
+}
+
+void BasePerigeeFilteringNode::m_acceptIt()
+{
+  m_nStatus=1;
+}
+
+bool BasePerigeeFilteringNode::m_isAccepted()
+{
+  return (m_nStatus==1);
+}
+
+void BasePerigeeFilteringNode::m_runFilter(double* Rk, double* Gk)
+{
+  double Kk[5][2];
+  int i,j,m,ind;
+
+  for(i=0;i<5;i++)
+    {
+      for(j=0;j<2;j++)
+	{
+	  Kk[i][j]=0.0;
+	  for(m=0;m<2;m++) Kk[i][j]+=m_B[m][i]*m_D[m][j];
+	}
+    }
+  for(i=0;i<5;i++) Rk[i]+=Kk[i][0]*m_resid[0]+Kk[i][1]*m_resid[1];
+  ind=0;
+  for(j=0;j<5;j++)
+    for(i=0;i<=j;i++)
+      {
+	Gk[ind]-=Kk[i][0]*m_B[0][j]+Kk[i][1]*m_B[1][j];
+	ind++;
+      }
+}
+
+void BasePerigeeFilteringNode::m_applyMultScatt(double* Rk,double* Gk)
+{
+  double s2,pt,sint,l1;
+  double F[5][2];
+  double rk;
+
+  pt=-0.3/Rk[0];
+  sint=1+Rk[4]*Rk[4];
+  pt*=(pt*sint);
+  s2=m_EffSigmaMS*m_EffSigmaMS/pt;
+  rk=Rk[0]*Rk[0]*m_Rho*m_Rho;
+  l1=1.0/(1.0-4*rk);
+  F[0][0]=0.0;
+  F[0][1]=-Rk[0]*Rk[4];
+  F[1][0]=m_Rho*(1-0.5*rk);
+  F[1][1]=rk*Rk[4]/Rk[0];
+  F[2][0]=(1-2*rk)*l1;
+  F[2][1]=-F[0][1]*2*m_Rho*(1-0.5*rk)*l1;
+  F[3][0]=-F[0][1]*m_Rho*l1;
+  F[3][1]=m_Rho*sint;
+  F[4][0]=0.0;
+  F[4][1]=-sint;
+  int i;
+  sint=sqrt(sint);
+  for(i=0;i<5;i++) F[i][0]*=sint;
+  Gk[0]+=s2*F[0][1]*F[0][1];
+  Gk[1]+=s2*F[0][1]*F[1][1];
+  Gk[2]+=s2*(F[1][0]*F[1][0]+F[1][1]*F[1][1]);
+  Gk[3]+=s2*F[0][1]*F[2][1];
+  Gk[4]+=s2*(F[1][0]*F[2][0]+F[1][1]*F[2][1]);
+  Gk[5]+=s2*(F[2][0]*F[2][0]+F[2][1]*F[2][1]);
+  Gk[6]+=s2*F[0][1]*F[3][1];
+  Gk[7]+=s2*(F[1][0]*F[3][0]+F[1][1]*F[3][1]);
+  Gk[8]+=s2*(F[2][0]*F[3][0]+F[2][1]*F[3][1]);
+  Gk[9]+=s2*(F[3][0]*F[3][0]+F[3][1]*F[3][1]);
+  Gk[10]+=s2*F[0][1]*F[4][1];
+  Gk[11]+=s2*F[1][1]*F[4][1];
+  Gk[12]+=s2*F[2][1]*F[4][1];
+  Gk[13]+=s2*F[3][1]*F[4][1];
+  Gk[14]+=s2*F[4][1]*F[4][1];
+}
+
+void BasePerigeeFilteringNode::m_applyEnergyLoss(double* Rk, double* Gk, int dir)
+{
+  double alpha,k0,rho2,rho3,rho4,sigma2;
+
+  alpha=m_EffRadLength*(1-0.5*m_EffRadLength);
+  sigma2=Rk[0]*Rk[0]*m_EffRadLength*(0.415-0.744*m_EffRadLength);
+  rho2=m_Rho*m_Rho;
+  rho3=m_Rho*rho2;
+  rho4=m_Rho*rho3;
+  k0=Rk[0]*dir*alpha;
+  Rk[0]+=k0;
+  Rk[1]+=-k0*rho2;
+  Rk[2]+=-k0*2*m_Rho;
+  Gk[0]+=sigma2;
+  Gk[1]+=-rho2*sigma2;
+  Gk[2]+=rho4*sigma2;
+  Gk[3]+=-2*m_Rho*sigma2;
+  Gk[4]+=2*rho3*sigma2;
+  Gk[5]+=4*rho2*sigma2;
+}
+
+
+double BarrelPerigeeFilteringNode::m_getChi2(double* Rk, double* Gk)
+{
+  double chi2=0.0,zres,detr;
+  double H[2][5];
+  double V[2][2];
+  
+  double h1,h2,h3,sinz,cosz;
+
+  zres=m_yZ-Rk[3];
+  h3=zres*2*Rk[0]/Rk[4];
+  sinz=sin(h3);cosz=cos(h3);
+  h1=1.0/(1.0-2*Rk[1]*Rk[0]);
+  h2=(Rk[1]-m_Ri)*(Rk[1]+m_Ri);
+  H[0][0]=h1*h1*h2;
+  H[0][1]=h1+2*Rk[0]*Rk[0]*H[0][0];
+  H[0][2]=-m_Ri*cos(m_yPhi-Rk[2]);
+  H[1][0]=0.5*(sinz-h3*cosz)/(Rk[0]*Rk[0]);
+  H[1][2]=m_Ri*sin(m_yPhi-Rk[2]);
+  H[1][3]=cosz/Rk[4];
+  H[1][4]=zres*cosz/(Rk[4]*Rk[4]);
+
+  m_B[0][0]=H[0][0]*Gk[0]+H[0][1]*Gk[1]+H[0][2]*Gk[3];
+  m_B[0][1]=H[0][0]*Gk[1]+H[0][1]*Gk[2]+H[0][2]*Gk[4];
+  m_B[0][2]=H[0][0]*Gk[3]+H[0][1]*Gk[4]+H[0][2]*Gk[5];
+  m_B[0][3]=H[0][0]*Gk[6]+H[0][1]*Gk[7]+H[0][2]*Gk[8];
+  m_B[0][4]=H[0][0]*Gk[10]+H[0][1]*Gk[11]+H[0][2]*Gk[12];
+
+  m_B[1][0]=H[1][0]*Gk[0]+H[1][2]*Gk[3]+H[1][3]*Gk[6]+H[1][4]*Gk[10];
+  m_B[1][1]=H[1][0]*Gk[1]+H[1][2]*Gk[4]+H[1][3]*Gk[7]+H[1][4]*Gk[11];
+  m_B[1][2]=H[1][0]*Gk[3]+H[1][2]*Gk[5]+H[1][3]*Gk[8]+H[1][4]*Gk[12];
+  m_B[1][3]=H[1][0]*Gk[6]+H[1][2]*Gk[8]+H[1][3]*Gk[9]+H[1][4]*Gk[13];
+  m_B[1][4]=H[1][0]*Gk[10]+H[1][2]*Gk[12]+H[1][3]*Gk[13]+H[1][4]*Gk[14];
+
+  V[0][0]=m_sigmaPhi*H[0][2];
+  V[0][0]=V[0][0]*V[0][0];
+  V[0][1]=H[0][2]*H[1][2]*m_sigmaPhi*m_sigmaPhi;V[1][0]=V[0][1];
+  V[1][1]=m_sigmaZ*m_sigmaZ*H[1][3]*H[1][3]+m_sigmaPhi*m_sigmaPhi*
+    H[1][2]*H[1][2];
+
+  V[0][0]+=m_B[0][0]*H[0][0]+m_B[0][1]*H[0][1]+m_B[0][2]*H[0][2];
+  V[1][1]+=m_B[1][0]*H[1][0]+m_B[1][2]*H[1][2]+m_B[1][3]*H[1][3]+
+    m_B[1][4]*H[1][4];
+  V[0][1]+=m_B[0][0]*H[1][0]+m_B[0][2]*H[1][2]+m_B[0][3]*H[1][3]+
+    m_B[0][4]*H[1][4];
+  V[1][0]+=m_B[1][0]*H[0][0]+m_B[1][1]*H[0][1]+m_B[1][2]*H[0][2];
+  detr=V[0][0]*V[1][1]-V[0][1]*V[0][1];
+  detr=1.0/detr;
+  m_D[0][0]=V[1][1]*detr;m_D[1][1]=V[0][0]*detr;m_D[0][1]=-V[0][1]*detr;
+  m_D[1][0]=m_D[0][1];
+  m_resid[0]=-H[1][2]-h1*(Rk[1]-Rk[0]*(Rk[1]*Rk[1]+m_Ri*m_Ri));
+  m_resid[1]=H[0][2]+0.5*sinz/Rk[0];
+  chi2=m_resid[0]*m_resid[0]*m_D[0][0]+2.0*m_resid[0]*m_resid[1]*m_D[0][1]+
+    m_resid[1]*m_resid[1]*m_D[1][1];
+  return chi2;
+}
+
+void BarrelPerigeeFilteringNode::m_applyMultScatt(double* Rk, double* Gk)
+{
+  m_EffRadLength=m_getEffRadLength(Rk);
+  m_EffSigmaMS=0.0136*sqrt(m_EffRadLength)*
+    (1.0+0.038*log(m_EffRadLength));
+  m_Rho=m_Ri;
+  BasePerigeeFilteringNode::m_applyMultScatt(Rk,Gk);
+}
+
+void BarrelPerigeeFilteringNode::m_applyEnergyLoss(double* Rk, double* Gk, int dir)
+{
+  m_EffRadLength=m_getEffRadLength(Rk);
+  m_Rho=m_Ri;
+  BasePerigeeFilteringNode::m_applyEnergyLoss(Rk,Gk,dir);
+}
+
+void BarrelPerigeeFilteringNode::m_runFilter(double* Rk, double* Gk)
+{
+  BasePerigeeFilteringNode::m_runFilter(Rk,Gk);
+}
+
+int BarrelPerigeeFilteringNode::m_getNdof()
+{
+  return 2;
+}
+
+double BarrelPerigeeFilteringNode::m_getEffRadLength(double* Rk)
+{
+  const double x0=0.022;
+
+  double x0eff=x0*sqrt(1+Rk[4]*Rk[4]);
+  return x0eff;
+}
+
+double DiscPerigeeFilteringNode::m_getChi2(double* Rk, double* Gk)
+{
+  double chi2=0.0,zres,detr;
+  double H[2][5];
+  double V[2][2];  
+  double h1,h2,h3,sinz,cosz,dhdR1,dhdR2;
+
+  zres=m_Zi-Rk[3];
+  h3=zres*2*Rk[0]/Rk[4];
+  sinz=sin(h3);cosz=cos(h3);
+  h1=1.0/(1.0-2*Rk[1]*Rk[0]);
+  h2=(Rk[1]-m_yR)*(Rk[1]+m_yR);
+  dhdR1=sin(m_yPhi-Rk[2]);
+  dhdR2=cos(m_yPhi-Rk[2]);
+  H[0][0]=h1*h1*h2;
+  H[0][1]=h1+2*Rk[0]*Rk[0]*H[0][0];
+  H[0][2]=-m_yR*dhdR2;
+  H[1][0]=0.5*(sinz-h3*cosz)/(Rk[0]*Rk[0]);
+  H[1][2]=m_yR*dhdR1;
+  H[1][3]=cosz/Rk[4];
+  H[1][4]=zres*cosz/(Rk[4]*Rk[4]);
+  dhdR1=sin(m_yPhi-Rk[2]);
+  dhdR2=cos(m_yPhi-Rk[2]);
+
+  m_B[0][0]=H[0][0]*Gk[0]+H[0][1]*Gk[1]+H[0][2]*Gk[3];
+  m_B[0][1]=H[0][0]*Gk[1]+H[0][1]*Gk[2]+H[0][2]*Gk[4];
+  m_B[0][2]=H[0][0]*Gk[3]+H[0][1]*Gk[4]+H[0][2]*Gk[5];
+  m_B[0][3]=H[0][0]*Gk[6]+H[0][1]*Gk[7]+H[0][2]*Gk[8];
+  m_B[0][4]=H[0][0]*Gk[10]+H[0][1]*Gk[11]+H[0][2]*Gk[12];
+
+  m_B[1][0]=H[1][0]*Gk[0]+H[1][2]*Gk[3]+H[1][3]*Gk[6]+H[1][4]*Gk[10];
+  m_B[1][1]=H[1][0]*Gk[1]+H[1][2]*Gk[4]+H[1][3]*Gk[7]+H[1][4]*Gk[11];
+  m_B[1][2]=H[1][0]*Gk[3]+H[1][2]*Gk[5]+H[1][3]*Gk[8]+H[1][4]*Gk[12];
+  m_B[1][3]=H[1][0]*Gk[6]+H[1][2]*Gk[8]+H[1][3]*Gk[9]+H[1][4]*Gk[13];
+  m_B[1][4]=H[1][0]*Gk[10]+H[1][2]*Gk[12]+H[1][3]*Gk[13]+H[1][4]*Gk[14];
+
+  V[0][0]=m_sigmaPhi*m_sigmaPhi*H[0][2]*H[0][2]+
+    m_sigmaR*m_sigmaR*dhdR1*dhdR1;
+  V[0][1]=H[0][2]*H[1][2]*m_sigmaPhi*m_sigmaPhi+
+    dhdR1*dhdR2*m_sigmaR*m_sigmaR;
+  V[1][0]=V[0][1];
+  V[1][1]=m_sigmaR*m_sigmaR*dhdR2*dhdR2+m_sigmaPhi*m_sigmaPhi*
+    H[1][2]*H[1][2];
+
+  V[0][0]+=m_B[0][0]*H[0][0]+m_B[0][1]*H[0][1]+m_B[0][2]*H[0][2];
+  V[1][1]+=m_B[1][0]*H[1][0]+m_B[1][2]*H[1][2]+m_B[1][3]*H[1][3]+
+    m_B[1][4]*H[1][4];
+  V[0][1]+=m_B[0][0]*H[1][0]+m_B[0][2]*H[1][2]+m_B[0][3]*H[1][3]+
+    m_B[0][4]*H[1][4];
+  V[1][0]+=m_B[1][0]*H[0][0]+m_B[1][1]*H[0][1]+m_B[1][2]*H[0][2];
+  detr=V[0][0]*V[1][1]-V[0][1]*V[0][1];
+  detr=1.0/detr;
+  m_D[0][0]=V[1][1]*detr;m_D[1][1]=V[0][0]*detr;m_D[0][1]=-V[0][1]*detr;
+  m_D[1][0]=m_D[0][1];
+  m_resid[0]=-H[1][2]-h1*(Rk[1]-Rk[0]*(Rk[1]*Rk[1]+m_yR*m_yR));
+  m_resid[1]=H[0][2]+0.5*sinz/Rk[0];
+  chi2=m_resid[0]*m_resid[0]*m_D[0][0]+2.0*m_resid[0]*m_resid[1]*m_D[0][1]+
+    m_resid[1]*m_resid[1]*m_D[1][1];
+
+  return chi2;
+}
+
+void DiscPerigeeFilteringNode::m_applyMultScatt(double* Rk, double* Gk)
+{
+  m_EffRadLength=m_getEffRadLength(Rk);
+  m_EffSigmaMS=0.0136*sqrt(m_EffRadLength)*
+    (1.0+0.038*log(m_EffRadLength));
+  m_Rho=m_yR;
+  BasePerigeeFilteringNode::m_applyMultScatt(Rk,Gk);
+}
+
+void DiscPerigeeFilteringNode::m_applyEnergyLoss(double* Rk, double* Gk, int dir)
+{
+  m_EffRadLength=m_getEffRadLength(Rk);
+  m_Rho=m_yR;
+  BasePerigeeFilteringNode::m_applyEnergyLoss(Rk,Gk,dir);
+}
+
+void DiscPerigeeFilteringNode::m_runFilter(double* Rk, double* Gk)
+{
+  BasePerigeeFilteringNode::m_runFilter(Rk,Gk);
+}
+
+int DiscPerigeeFilteringNode::m_getNdof()
+{
+  return 2;
+}
+
+double DiscPerigeeFilteringNode::m_getEffRadLength(double* Rk)
+{
+  const double x0=0.022;
+
+  double x0eff=x0/(fabs(Rk[4])*sqrt(1+Rk[4]*Rk[4]));
+  return x0eff;
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigDkfTrackMakerTool.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigDkfTrackMakerTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f54d680f9684be1be37879aa2f6507b7141759cf
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigDkfTrackMakerTool.cxx
@@ -0,0 +1,355 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigDkfTrackMakerTool tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 17.03.2009 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+#include "StoreGate/StoreGateSvc.h" 
+#include "GaudiKernel/ToolFactory.h"
+#include "StoreGate/DataHandle.h"
+
+#include "TrigInDetEvent/TrigSiSpacePoint.h"
+
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "InDetPrepRawData/SCT_Cluster.h"
+#include "InDetPrepRawData/PixelCluster.h"
+#include "InDetRIO_OnTrack/SCT_ClusterOnTrack.h"
+#include "InDetRIO_OnTrack/PixelClusterOnTrack.h"
+
+#include "TrigInDetToolInterfaces/ITrigDkfTrackMakerTool.h"
+#include "TrigInDetTrackFitter/TrigDkfTrackMakerTool.h"
+#include "TrkSurfaces/Surface.h"
+#include "TrkSurfaces/TrapezoidBounds.h"
+
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+
+
+TrigDkfTrackMakerTool::TrigDkfTrackMakerTool(const std::string& t, 
+					     const std::string& n,
+					     const IInterface*  p ): AthAlgTool(t,n,p)
+{
+  declareInterface< ITrigDkfTrackMakerTool >( this );
+  m_idHelper=NULL;
+}
+
+StatusCode TrigDkfTrackMakerTool::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+  MsgStream athenaLog(msgSvc(), name());
+
+  athenaLog << MSG::INFO <<"In initialize..."<<endreq; 
+
+  StoreGateSvc* detStore;
+  sc = service("DetectorStore", detStore);
+  if ( sc.isFailure() ) { 
+    athenaLog << MSG::FATAL << "DetStore service not found" << endreq; 
+    return StatusCode::FAILURE; 
+  }
+
+ if (detStore->retrieve(m_idHelper, "AtlasID").isFailure()) {
+    athenaLog << MSG::FATAL << "Could not get AtlasDetectorID helper AtlasID" << endreq;
+    return StatusCode::FAILURE;
+  }  
+
+ // Get SCT & pixel Identifier helpers
+
+  if (detStore->retrieve(m_pixelId, "PixelID").isFailure()) { 
+     athenaLog << MSG::FATAL << "Could not get Pixel ID helper" << endreq;
+     return StatusCode::FAILURE;  
+  }
+  if (detStore->retrieve(m_sctId, "SCT_ID").isFailure()) {  
+     athenaLog << MSG::FATAL << "Could not get SCT ID helper" << endreq;
+     return StatusCode::FAILURE;
+  }
+  sc = detStore->retrieve(m_pixelManager);  
+  if( sc.isFailure() ) 
+   {
+      athenaLog << MSG::ERROR << "Could not retrieve Pixel DetectorManager from detStore."<<endreq; 
+      return sc;
+   } 
+  sc = detStore->retrieve(m_SCT_Manager);
+  if( sc.isFailure() ) 
+    {
+      athenaLog << MSG::ERROR << "Could not retrieve SCT DetectorManager from detStore." << endreq;
+      return sc;
+    } 
+
+  athenaLog << MSG::INFO << "TrigDkfTrackMakerTool constructed "<< endreq;
+  return sc;
+}
+
+StatusCode TrigDkfTrackMakerTool::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+TrigDkfTrackMakerTool::~TrigDkfTrackMakerTool()
+{
+
+}
+
+bool TrigDkfTrackMakerTool::createDkfTrack(std::vector<const TrigSiSpacePoint*>& siSpacePoints, 
+					   std::vector<Trk::TrkBaseNode*>& vpTrkNodes,
+					   double DChi2)
+{
+  const double radLength=0.022;
+
+  std::vector<const TrigSiSpacePoint*>::iterator pSPIt,lastSPIt;
+
+  double C[3],N[3],M[3][3];int i;
+  Amg::Vector3D mx,my,mz;
+
+  MsgStream athenaLog(msgSvc(), name());
+  int outputLevel = msgSvc()->outputLevel( name() );
+
+  vpTrkNodes.clear();
+
+  if(siSpacePoints.size()==0) 
+  {
+    if (outputLevel <= MSG::WARNING) 
+      athenaLog << MSG::ERROR << "Cannot create a DKF track -- TrigInDetTrack has no hits" 
+		<< endreq;
+    return false;
+  }
+  pSPIt=siSpacePoints.begin();lastSPIt=siSpacePoints.end();
+  for(; pSPIt != lastSPIt; pSPIt++) 
+    {
+      const TrigSiSpacePoint* pSP=(*pSPIt);
+
+      // std::cout<<"SP layer="<<pSP->layer()<<" r="<<pSP->r()<<" phi="<<pSP->phi()<<" z="<<pSP->z()<<std::endl;
+
+      Identifier ID=pSP->identify();
+      if(m_idHelper->is_sct(ID))
+	{
+	  const InDet::SiCluster *pCL[2];
+	  pCL[0] = pSP->clusters().first;
+	  pCL[1] = pSP->clusters().second;
+	  if((pCL[0]==NULL)||(pCL[1]==NULL)) continue;
+
+	  IdentifierHash idHash[2];
+	  InDetDD::SiDetectorElement* pEL[2];
+	  double RadVec[2];
+	  int index[2];
+	  for(i=0;i<2;i++)
+	    {
+	      idHash[i]=m_sctId->wafer_hash(m_sctId->wafer_id(pCL[i]->identify()));
+	      pEL[i]=m_SCT_Manager->getDetectorElement(idHash[i]);	      
+	      const Trk::Surface& rSurf=pEL[i]->surface();
+
+	      // const Trk::Surface& rSurf=pCL[i]->detectorElement()->surface();
+	      RadVec[i]=rSurf.center().mag();
+	      index[i]=i;
+	    }
+	  if(RadVec[0]>RadVec[1])
+	    {
+	      index[0]=1;index[1]=0;
+	    }
+	  for (int iClusInSP=0; iClusInSP<2; iClusInSP++)
+	    {
+	      const Trk::Surface& rSurf=pEL[index[iClusInSP]]->surface();
+	      //const Trk::Surface& rSurf=pCL[i]->detectorElement()->surface();
+	      N[0]=rSurf.normal().x();
+	      N[1]=rSurf.normal().y();
+	      N[2]=rSurf.normal().z();
+	      C[0]=rSurf.center().x();
+	      C[1]=rSurf.center().y();
+	      C[2]=rSurf.center().z();
+
+	      mx=rSurf.transform().rotation().block(0,0,3,1);
+	      my=rSurf.transform().rotation().block(0,1,3,1);
+	      mz=rSurf.transform().rotation().block(0,2,3,1);
+	      for(i=0;i<3;i++) 
+		{
+		  M[i][0]=mx[i];M[i][1]=my[i];M[i][2]=mz[i];
+		}
+	      Trk::TrkPlanarSurface* pS = new Trk::TrkPlanarSurface(C,N,M,radLength,
+								    &(pEL[index[iClusInSP]]->surface()));
+	      //std::cout<<"created SCT surface"<<std::endl;pS->m_report();
+	      /*
+	      double locCov;
+	      try {
+		const Trk::ErrorMatrix& errMatRef=pCL[index[iClusInSP]]->localErrorMatrix();
+		locCov=errMatRef.covariance()[0][0];
+	      }
+	      catch(Trk::PrepRawDataUndefinedVariable) {
+		locCov=pEL[index[iClusInSP]]->phiPitch();
+		locCov=locCov*locCov/12.0;
+	      }
+	      // override
+	      
+	      locCov=pEL[index[iClusInSP]]->phiPitch();
+	      locCov=locCov*locCov/12.0;
+	      */
+
+	      if(pEL[index[iClusInSP]]->design().shape()!=InDetDD::Trapezoid)
+		{
+		  //vpTrkNodes.push_back(new Trk::TrkClusterNode(pS,DChi2,pCL[index[iClusInSP]]->localPosition()[0],locCov));
+		  vpTrkNodes.push_back(new Trk::TrkClusterNode(pS,DChi2,pCL[index[iClusInSP]]));
+		}
+	      else
+		{	  
+		  const Trk::SurfaceBounds& rBounds=rSurf.bounds();
+		  const Trk::TrapezoidBounds& ecBounds=
+		    dynamic_cast<const Trk::TrapezoidBounds&>(rBounds);
+		  double R=(ecBounds.maxHalflengthX()+ecBounds.minHalflengthX())*
+		    ecBounds.halflengthY()/
+		    (ecBounds.maxHalflengthX()-ecBounds.minHalflengthX());
+		  vpTrkNodes.push_back(new Trk::TrkEndCapClusterNode(pS,DChi2,pCL[index[iClusInSP]],R));
+
+		  //  vpTrkNodes.push_back(new Trk::TrkEndCapClusterNode(pS,DChi2,R,pCL[index[iClusInSP]]->localPosition()[0],locCov));
+		}
+	    }
+	}
+      else if(m_idHelper->is_pixel(ID))
+	{
+	  const InDet::SiCluster* pCL=pSP->clusters().first;
+	  
+	  if(pCL)
+	    {
+	      
+	      const IdentifierHash idHash=
+		m_pixelId->wafer_hash(m_pixelId->wafer_id(pCL->identify()));
+	      InDetDD::SiDetectorElement* pEL=m_pixelManager->getDetectorElement(idHash);
+	      const Trk::Surface& rSurf=pEL->surface();
+	      
+	      //const Trk::Surface& rSurf=pCL->detectorElement()->surface();
+
+	      N[0]=rSurf.normal().x();
+	      N[1]=rSurf.normal().y();
+	      N[2]=rSurf.normal().z();
+	      C[0]=rSurf.center().x();
+	      C[1]=rSurf.center().y();
+	      C[2]=rSurf.center().z();
+	      mx=rSurf.transform().rotation().block(0,0,3,1);
+	      my=rSurf.transform().rotation().block(0,1,3,1);
+	      mz=rSurf.transform().rotation().block(0,2,3,1);
+	      for(i=0;i<3;i++) 
+		{
+		  M[i][0]=mx[i];M[i][1]=my[i];M[i][2]=mz[i];
+		}
+	      Trk::TrkPlanarSurface* pS = new Trk::TrkPlanarSurface(C,N,M,radLength,&(pEL->surface()));
+	      /*
+	      std::cout<<"created PIX surface"<<std::endl;
+	      std::cout<<"local position: "<<pCL->localPosition()[0]<<" "<<pCL->localPosition()[1]<<std::endl;
+	      pS->m_report();
+	      */
+	      //	      double locPos[2];
+	      /*
+	      double locCov[4];
+	      try {
+		const Trk::ErrorMatrix& errMatRef=pCL->localErrorMatrix();
+		locCov[0]=errMatRef.covariance()[0][0];
+		locCov[1]=errMatRef.covariance()[0][1];
+		locCov[2]=errMatRef.covariance()[1][0];
+		locCov[3]=errMatRef.covariance()[1][1];
+	      }
+	      catch(Trk::PrepRawDataUndefinedVariable) {
+		//locCov[0]=pEL->phiPitch()*pEL->phiPitch()/12.0;
+		locCov[1]=0.0;locCov[2]=0.0;
+		//locCov[3]=pEL->etaPitch()*pEL->etaPitch()/12.0;
+		locCov[3]=0.3*0.3;locCov[0]=0.012*0.012;
+	      }
+	      */
+	      // override
+	      /*
+	      locCov[0]=pEL->phiPitch()*pEL->phiPitch()/12.0;
+	      locCov[1]=0.0;locCov[2]=0.0;
+	      locCov[3]=pEL->etaPitch()*pEL->etaPitch()/12.0;
+	      locPos[0]=pCL->localPosition()[0];
+	      locPos[1]=pCL->localPosition()[1];    
+	      */
+	      //vpTrkNodes.push_back(new Trk::TrkPixelNode(pS,DChi2,locPos,locCov));
+	      vpTrkNodes.push_back(new Trk::TrkPixelNode(pS,DChi2,pCL));
+	    }
+	}
+    }
+  if (outputLevel <= MSG::DEBUG) 
+    athenaLog << MSG::DEBUG << vpTrkNodes.size()<<" filtering nodes created"<<endreq;
+
+  return true;
+}
+
+bool TrigDkfTrackMakerTool::createDkfTrack(const Trk::Track& track, 
+		std::vector<Trk::TrkBaseNode*>& vpTrkNodes,
+		double DChi2) {
+	vpTrkNodes.clear();
+
+	if(track.measurementsOnTrack()->size()==0) 
+	{
+		ATH_MSG_ERROR("Cannot create a DKF track -- Trk::Track has no hits");
+		return false;
+	}
+	for (auto tMOT = track.measurementsOnTrack()->begin(); tMOT != track.measurementsOnTrack()->end(); ++tMOT) {
+		const Trk::Surface& rSurf=(*tMOT)->associatedSurface();
+		constexpr double radLength=0.022;
+		double C[3],N[3],M[3][3];
+		Amg::Vector3D mx,my,mz;
+		N[0]=rSurf.normal().x();
+		N[1]=rSurf.normal().y();
+		N[2]=rSurf.normal().z();
+		C[0]=rSurf.center().x();
+		C[1]=rSurf.center().y();
+		C[2]=rSurf.center().z();
+		mx=rSurf.transform().rotation().block(0,0,3,1);
+		my=rSurf.transform().rotation().block(0,1,3,1);
+		mz=rSurf.transform().rotation().block(0,2,3,1);
+		for(int i=0;i<3;i++) {
+		  M[i][0]=mx[i];M[i][1]=my[i];M[i][2]=mz[i];
+		}
+		Trk::TrkPlanarSurface* pS = new Trk::TrkPlanarSurface(C,N,M,radLength, &(rSurf));
+
+
+
+		const InDet::SiClusterOnTrack* siCLOT = dynamic_cast<const InDet::SiClusterOnTrack*>(*tMOT);
+		if (siCLOT==nullptr) {
+			ATH_MSG_VERBOSE("siCLOT is null");
+			continue;
+		}
+		const InDet::SiCluster* siCL = dynamic_cast<const InDet::SiCluster*>(siCLOT->prepRawData());
+		if (siCL==nullptr) {
+			ATH_MSG_VERBOSE("siCL is null");
+			continue;
+		}
+		Identifier id = (*tMOT)->associatedSurface().associatedDetectorElement()->identify();
+		ATH_MSG_DEBUG("Identifier: " << m_idHelper->print_to_string(id));
+		if(m_idHelper->is_sct(id)) {
+			const InDetDD::SiDetectorElement* sctElement = dynamic_cast<const InDetDD::SiDetectorElement*> 
+				((*tMOT)->associatedSurface().associatedDetectorElement());
+			if(sctElement->design().shape()==InDetDD::Trapezoid) //SCT Endcap
+			{
+				ATH_MSG_DEBUG("SCT endcap node");
+				const Trk::SurfaceBounds& rBounds=rSurf.bounds();
+				const Trk::TrapezoidBounds& ecBounds=	dynamic_cast<const Trk::TrapezoidBounds&>(rBounds);
+				double R=(ecBounds.maxHalflengthX()+ecBounds.minHalflengthX())*
+					ecBounds.halflengthY()/(ecBounds.maxHalflengthX()-ecBounds.minHalflengthX());
+				vpTrkNodes.push_back(new Trk::TrkEndCapClusterNode(pS,DChi2,siCL,R));
+			}
+			else {//SCT Barrel 
+				ATH_MSG_DEBUG("SCT barrel node");
+				vpTrkNodes.push_back(new Trk::TrkClusterNode(pS,DChi2,siCL));
+			}
+		}
+		else if (m_idHelper->is_pixel(id)) {//Pixel 
+			ATH_MSG_DEBUG("Pixel node");
+			vpTrkNodes.push_back(new Trk::TrkPixelNode(pS,DChi2,siCL));
+		}
+	}
+	ATH_MSG_DEBUG(vpTrkNodes.size()<<" filtering nodes created");
+
+	return true;
+}
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetBremDetectionTool.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetBremDetectionTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5b21604a997bb2458023bda84a3e98d163ec68df
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetBremDetectionTool.cxx
@@ -0,0 +1,898 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//////////////////////////////////////////////////////////////////
+// TrigInDetBremDetectionTool.cxx
+//   Source file for TrigInDetBremDetectionTool
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+// Dmitry.Emeliyanov@cern.ch
+///////////////////////////////////////////////////////////////////
+
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+#include "TrigInDetTrackFitter/TrigInDetBremDetectionTool.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+#include <cmath>
+#include <cstring>
+using std::memset;
+
+//#define IDE_DEBUG 1
+
+TrigInDetBremDetectionTool::TrigInDetBremDetectionTool(const std::string& t,const std::string& n,const IInterface* p) :
+  AthAlgTool (t,n,p),
+  m_log(msgSvc(), n),
+  m_outputLevel(1),
+  m_minDistance(10.0),
+  m_P0(0.6),
+  m_SignificanceCut(4.5)
+{
+  declareProperty("minDistance",m_minDistance);
+  declareProperty("noBremProbability",m_P0);
+  declareProperty("MinSignificance",m_SignificanceCut);
+  declareInterface<ITrigInDetBremDetectionTool>( this );
+  m_pLS=NULL;
+}
+
+// destructor
+TrigInDetBremDetectionTool::~TrigInDetBremDetectionTool()
+{
+
+}
+// initialize
+StatusCode TrigInDetBremDetectionTool::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  m_log.setLevel(outputLevel());            // individual outputlevel not known before initialise
+  m_outputLevel=msgSvc()->outputLevel( name() );
+  m_Threshold=2.0*log(m_P0/(1.0-m_P0));
+
+  m_log << MSG::INFO << "initialize() successful in " << name() << endreq;
+  m_log << MSG::INFO << "Input detection threshold is set to " << m_Threshold << endreq;
+
+  return sc;
+}
+
+// finalize
+StatusCode TrigInDetBremDetectionTool::finalize()
+{
+  if(m_pLS!=NULL) delete m_pLS;
+
+  m_log << MSG::INFO << "finalize() successful in " << name() << endreq;
+  return StatusCode::SUCCESS;
+}
+
+void TrigInDetBremDetectionTool::reset()
+{
+  m_totalPath=0.0;
+  m_lsmSize=0;m_resSizes.clear();m_resSize=0;
+  memset(&m_A[0][0],0,sizeof(m_A));
+  memset(&m_MG[0][0],0,sizeof(m_MG));
+  memset(&m_S[0][0],0,sizeof(m_S));
+  if(m_pLS!=NULL) delete m_pLS;m_pLS=NULL;
+}
+
+bool TrigInDetBremDetectionTool::addNewPoint(Trk::TrkTrackState* pTS,
+					     Trk::TrkBaseNode* pN, Trk::TrkPlanarSurface* pS, double F[5][5],
+					     double delta)
+{
+  int i,j,dim,k;
+  double res[5];
+  double K[5][2];
+  double H[2][5];
+  double S[2][2];
+  double mu[5][5];
+  double HF[2][5];
+  double M[5];
+  double lP[3],gP[3];
+
+
+  m_totalPath+=fabs(delta);
+
+  dim=pN->m_getKalmanGain(K);
+  dim=pN->m_getMeasurementMatrix(H);
+  dim=pN->m_getInverseResidualVariance(S);
+  dim=pN->m_getResiduals(res);
+
+#ifdef IDE_DEBUG
+
+  m_log<<MSG::INFO<<"new measurement, size="<<dim<< endreq;
+  m_log<< MSG::INFO << " Accumulated path = "<< m_totalPath  << endreq;
+
+  printf("Jacobian:\n");
+  for(i=0;i<5;i++)
+    {
+      for(j=0;j<5;j++)
+	printf("%E ",F[i][j]);
+      printf("\n");
+    }
+
+#endif
+
+  if(dim!=0)
+    {
+#ifdef IDE_DEBUG
+      printf("Measurement matrix:\n");
+      for(i=0;i<dim;i++)
+	{
+	  for(j=0;j<5;j++)
+	    printf("%E ",H[i][j]);
+	  printf("\n");
+	}  
+#endif
+      if(m_lsmSize!=0)
+	{
+	  m_resSizes.push_back(dim);
+	  for(i=0;i<dim;i++) 
+	    {
+	      m_R[m_resSize]=res[i];
+	      for(j=0;j<dim;j++) m_S[m_resSize][j]=S[i][j];
+	      m_resSize++;
+	    }
+	}
+      for(i=0;i<dim;i++)
+	for(j=0;j<5;j++)
+	  {
+	    HF[i][j]=0.0;
+	    for(k=0;k<5;k++) HF[i][j]+=H[i][k]*F[k][j];
+	  }
+      for(i=0;i<5;i++)
+	for(j=0;j<5;j++) 
+	  {
+	    mu[i][j]=F[i][j];
+	    for(k=0;k<dim;k++) mu[i][j]-=K[i][k]*HF[k][j];
+	  }
+    }
+  else
+    {
+      for(i=0;i<5;i++)
+	for(j=0;j<5;j++) 
+	  {
+	    mu[i][j]=F[i][j];
+	  }
+    }  
+  for(i=1;i<=m_lsmSize;i++)
+    {
+      for(k=0;k<5;k++)
+	{
+	  M[k]=0.0;
+	  for(j=0;j<5;j++) M[k]+=mu[k][j]*m_MG[j][i];
+	}
+      for(k=0;k<5;k++) m_MG[k][i]=M[k];
+    }
+  for(i=0;i<dim;i++)
+    {
+      for(k=1;k<=m_lsmSize;k++)
+	{
+	  m_A[i+m_resSize-dim][k-1]=0.0;
+	  for(j=0;j<5;j++) m_A[i+m_resSize-dim][k-1]+=HF[i][j]*m_MG[j][k];
+	}
+    }
+#ifdef IDE_DEBUG
+  printf("Matrix A:\n");
+  for(i=0;i<m_resSize;i++)
+    {
+      for(j=0;j<m_lsmSize;j++) printf("%E ",m_A[i][j]);
+      printf("\n");
+    }
+#endif
+  if(m_totalPath<m_minDistance) return false;
+
+  m_totalPath=0.0;
+  
+  m_lsmSize++;  
+
+  for(i=0;i<4;i++)
+  {
+    m_MG[i][m_lsmSize]=0.0;
+  }
+  m_MG[4][m_lsmSize]=1.0;
+
+  m_surfArray[m_lsmSize-1]=pS;
+
+  lP[0]=pTS->m_getTrackState(0);lP[1]=pTS->m_getTrackState(1);
+  lP[2]=0.0;
+  pS->m_transformPointToGlobal(lP,gP);
+  m_jX[m_lsmSize-1]=gP[0];m_jY[m_lsmSize-1]=gP[1];m_jZ[m_lsmSize-1]=gP[2]; 
+#ifdef IDE_DEBUG 
+  m_log << MSG::INFO << " Added new jump at "<<gP[0]<<" "<<gP[1]<<" "<<gP[2]<<endreq;
+#endif
+  return true;
+}
+
+bool TrigInDetBremDetectionTool::solve(int Sign)
+{
+  int i;
+  bool isSolved=false;
+  bool isFeasible=false;
+  int size=m_lsmSize-1;
+  int nIter;
+  double Chi2Opt;
+  double g[MAX_INP_SIZE];
+
+  m_sign=Sign;
+  m_size=m_lsmSize-1;
+  m_precomputeGain();
+  if(m_pLS!=NULL) delete m_pLS;m_pLS=NULL;
+
+  m_pLS=new LSMSolution(size);
+  for(i=0;i<m_size;i++)
+    {
+      m_pLS->m_fixVariable(i);
+    }
+  for(i=0;i<MAX_INP_SIZE;i++)
+    {
+      m_Zarray[i]=1;m_Parray[i]=0;
+    }
+  nIter=0;
+  while(!isSolved)
+    {
+      m_getGradient(m_pLS,g);
+#ifdef IDE_DEBUG
+      printf("++++ Gradient: ++++ Sign %d\n",Sign);
+      for(i=0;i<size;i++)
+	{
+	  printf("%E ",g[i]);
+	}
+      printf("\n");
+#endif
+      Chi2Opt=m_getCriterionValue(m_pLS);
+#ifdef IDE_DEBUG
+      printf("***** Criterion = %f ******\n",Chi2Opt);
+#endif
+      if(nIter>100) break;
+      if(m_isZempty()) 
+	{
+	  isSolved=true;break;
+	}
+      if(m_goodGradient(g))
+	{
+#ifdef IDE_DEBUG
+	  printf("Good gradient - solved\n");
+#endif
+	  isSolved=true;break;
+	}
+#ifdef IDE_DEBUG
+      else printf("Not good gradient - searching ...\n");
+#endif
+      int bestI=m_findBestDirection(g);
+#ifdef IDE_DEBUG
+      printf("Selected %d grad = %f\n",bestI,g[bestI]);
+#endif
+      m_Zarray[bestI]=0;m_Parray[bestI]=1;
+#ifdef IDE_DEBUG
+      for(i=0;i<m_size;i++) printf("%d ",m_Zarray[i]);
+      printf("\n");
+      for(i=0;i<m_size;i++) printf("%d ",m_Parray[i]);
+      printf("\n");
+#endif
+      isFeasible=false;
+     
+      while(!isFeasible)
+	{
+	  LSMSolution* pST=m_solveLSM();
+#ifdef IDE_DEBUG
+	  pST->m_report();
+#endif
+	  isFeasible=m_checkFeasibility(pST);
+	  if(!isFeasible)
+	    {
+#ifdef IDE_DEBUG
+	      printf("Non-feasible solution");
+#endif
+	      m_mixSolutions(pST,m_pLS);
+	      delete pST;
+	    }
+	  else
+	    {
+#ifdef IDE_DEBUG
+	      printf("Feasible solution\n");
+#endif
+	      delete m_pLS;
+	      m_pLS=pST;
+	    }
+	}
+      nIter++;
+    }
+  int nChanges=0;
+  bool nonZero=false;
+  
+  for(i=0;i<m_size;i++)
+    {
+      m_Zarray[i]=1;
+      if(!m_pLS->m_isOnConstraint(i))
+	{
+	  m_Zarray[i]=0;
+	  double utmp=(*m_pLS)[i];
+	  (*m_pLS)[i]=0.0;
+	  double Chi2Zero=m_getCriterionValue(m_pLS);
+	  if(m_outputLevel<=MSG::DEBUG)
+	    {
+	      m_log<<MSG::DEBUG<<i+1<<" Chi2* = "<<Chi2Opt<<" Chi20 = "<<Chi2Zero<<" Th="<<m_Threshold<<endreq;
+	    }
+	  (*m_pLS)[i]=utmp;
+	  double deltaChi2=Chi2Zero-Chi2Opt;
+	  if(deltaChi2<m_Threshold)
+	    {
+	      m_Zarray[i]=1;
+	      nChanges++;
+	    }
+	  else nonZero=true;
+
+	}
+    }
+  if((nChanges!=0)&&nonZero)
+    {
+      LSMSolution* pUS=m_solveLSM();
+      if(m_outputLevel<=MSG::DEBUG)
+	{
+	  m_log<<MSG::DEBUG<<"LSM Solution"<<endreq;
+	  pUS->m_report();
+	  Chi2Opt=m_getCriterionValue(pUS);
+	  m_log<<MSG::DEBUG<<"Criterion = "<<Chi2Opt<<endreq;
+	}
+      delete m_pLS;
+      m_pLS=pUS;
+    }
+  if(!nonZero)
+    {
+      delete m_pLS;
+      m_pLS=new LSMSolution(size);
+      for(i=0;i<m_size;i++)
+	{
+	  m_pLS->m_fixVariable(i);
+	}
+      if(m_outputLevel<=MSG::DEBUG)
+	{
+	  m_log<<MSG::DEBUG<<"LSM Solution"<<endreq;
+	  m_pLS->m_report();
+	  Chi2Opt=m_getCriterionValue(m_pLS);
+	  m_log<<MSG::DEBUG<<"Criterion = "<<Chi2Opt<<endreq;
+	}
+    }
+  return isSolved;
+}
+
+void TrigInDetBremDetectionTool::m_precomputeGain()
+{
+  int i,j,k;
+  memset(&m_K[0][0],0,sizeof(m_K));
+
+  int sJ,J0;
+
+  for(i=0;i<m_lsmSize-1;i++)
+    {
+      J0=0;
+      for(std::vector<int>::iterator iIt=m_resSizes.begin();iIt!=m_resSizes.end();++iIt)
+	{
+	  for(sJ=0;sJ<(*iIt);sJ++)
+	    {
+	      j=J0+sJ;
+	      m_K[i][j]=0.0;
+	      for(k=J0;k<J0+(*iIt);k++)
+		{
+		  m_K[i][j]+=m_A[k][i]*m_S[k][sJ];
+		}
+	      j++;
+	    }
+	  J0+=(*iIt);
+	}
+    }
+
+  for(i=0;i<m_lsmSize-1;i++)
+    for(j=i;j<m_lsmSize-1;j++)
+      {
+	m_W[i][j]=0.0;
+	for(k=0;k<m_resSize;k++) m_W[i][j]+=m_K[i][k]*m_A[k][j];
+	m_W[j][i]=m_W[i][j];
+      }
+}
+
+
+void TrigInDetBremDetectionTool::m_getGradient(LSMSolution* pLS, double g[])
+{
+  int i,j;
+
+  for(i=0;i<m_lsmSize-1;i++)
+    {
+      g[i]=0.0;
+      for(j=i;j<m_resSize;j++) g[i]+=m_K[i][j]*m_R[j];
+    }
+  for(i=0;i<m_lsmSize-1;i++)
+    {
+      for(j=0;j<m_lsmSize-1;j++) g[i]-=m_W[i][j]*(*pLS)[j];
+    }
+}
+
+bool TrigInDetBremDetectionTool::m_goodGradient(double* g)
+{
+  int i,np=0;
+  for(i=0;i<m_lsmSize-1;i++)
+    {
+      if(m_Zarray[i]==0) continue;
+      if(g[i]*m_sign>0.0) np++;
+    }
+  return (np==0);
+}
+
+int TrigInDetBremDetectionTool::m_findBestDirection(double* g)
+{
+  int i,bestI=0;
+  double maxGrad=-1.0;
+  for(i=0;i<m_lsmSize-1;i++)
+    {
+      if(g[i]*m_sign>maxGrad) 
+	{
+	  maxGrad=g[i]*m_sign;
+	  bestI=i;
+	}
+    }
+  return bestI;
+}
+
+bool TrigInDetBremDetectionTool::m_isZempty()
+{
+  int i;
+  
+  for(i=0;i<m_lsmSize-1;i++)
+    {
+      if(m_Zarray[i]==1) return false;
+    }
+  return true;
+}
+
+bool TrigInDetBremDetectionTool::CholeskyDecompositionNxN(double* a,int Size)
+{
+  int i,j,k;
+  double sum;
+  double* p=new double[Size];
+
+  for(i=0;i<Size;i++)
+    {
+      for(j=i;j<Size;j++)
+	{
+	  sum=a[i+j*Size];
+	  for(k=i-1;k>=0;k--)
+	    sum-=a[i+k*Size]*a[j+k*Size];
+	  if(i==j)
+	    {
+	      if(sum<=0.0)
+		{
+		  printf("Cholesky decomp. failed\n");delete[] p;
+		  return false;
+		}
+	      p[i]=sqrt(sum);
+	    }
+	  else a[j+i*Size]=sum/p[i];
+	}
+    }
+  for(i=0;i<Size;i++)
+    {
+      a[i+Size*i]=1.0/p[i];
+      for(j=i+1;j<Size;j++)
+	{
+	  sum=0.0;for(k=i;k<j;k++) sum-=a[j+Size*k]*a[k+Size*i];
+	  a[j+Size*i]=sum/p[j];
+	}
+    }
+  delete[] p;
+  return true;
+}
+
+
+bool TrigInDetBremDetectionTool::invertMatrixNxN(double* a, int size)
+{
+  double detr;
+  int i,j;
+  bool rc=false;
+
+  if(size==1)
+    {
+      a[0]=1.0/a[0];
+      rc=true;
+    }
+  else if(size==2)
+    {
+      detr=a[0]*a[3]-a[1]*a[2];
+      detr=1.0/detr;
+      double b[2][2];
+      b[0][0]=a[3]*detr;
+      b[1][0]=b[0][1]=-a[1]*detr;
+      b[1][1]=a[0]*detr;
+      for(i=0;i<2;i++) for(j=0;j<2;j++) a[i+j*size]=b[i][j];
+      rc=true;
+    }
+  else if(size==3)
+    {
+      double A[3][3],b[3][3],M[3];
+      for(i=0;i<3;i++) for(j=0;j<3;j++) A[i][j]=a[i+j*size];
+
+      M[0]=A[1][1]*A[2][2]-A[1][2]*A[1][2];
+      M[1]=A[0][1]*A[2][2]-A[1][2]*A[0][2];
+      M[2]=A[0][1]*A[1][2]-A[1][1]*A[0][2];
+      detr=A[0][0]*M[0]-A[0][1]*M[1]+A[0][2]*M[2];
+      detr=1.0/detr;
+      b[0][0]=M[0]*detr;
+      b[0][1]=b[1][0]=-M[1]*detr;
+      b[0][2]=b[2][0]=M[2]*detr;
+      b[1][1]=(A[0][0]*A[2][2]-A[0][2]*A[0][2])*detr;
+      b[1][2]=b[2][1]=-(A[0][0]*A[1][2]-A[0][1]*A[0][2])*detr;
+      b[2][2]=(A[0][0]*A[1][1]-A[0][1]*A[0][1])*detr;
+      for(i=0;i<3;i++) for(j=0;j<3;j++) a[i+j*size]=b[i][j];
+      rc=true;
+    }
+  else if(size>3)
+    {      
+      if(!CholeskyDecompositionNxN(a,size)) return false;
+
+      double* L=new double[size*size];
+      double* LT=new double[size*size];
+
+      memset(L,0,sizeof(double)*size*size);
+      memset(LT,0,sizeof(double)*size*size);
+
+      for(i=0;i<size;i++)
+		  for(j=0;j<=i;j++)
+		  {
+			  L[i+j*size]=a[i+j*size];
+			  LT[j+i*size]=L[i+size*j];
+		  }
+      for(i=0;i<size;i++)
+	  {
+		  for(j=i;j<size;j++)
+		  {
+			  double sum=0.0;
+			  for(int k=0;k<size;k++) sum+=LT[i+k*size]*L[k+j*size];
+			  a[j+i*size]=a[i+j*size]=sum;
+		  }
+	  }
+      delete[] L;
+      delete[] LT;
+      rc=true;
+    }
+  return rc;
+}
+
+
+LSMSolution* TrigInDetBremDetectionTool::m_solveLSM()
+{
+  LSMSolution* pLS=NULL;
+
+  int i,j,idxI,idxJ,newSize=m_size;
+  double W[MAX_INP_SIZE][MAX_INP_SIZE];
+  double P[MAX_INP_SIZE][MAX_INP_SIZE];
+  double E[MAX_INP_SIZE];
+  double chi2;
+  
+  memset(&W[0][0],0,sizeof(W));
+
+  for(i=0;i<m_size;i++) if(m_Zarray[i]==1) newSize--;
+
+  //  printf("newSize = %d\n",newSize);
+
+  idxI=-1;idxJ=-1;
+  for(i=0;i<m_size;i++)
+    {
+      if(m_Zarray[i]==1) continue;
+      idxI++;idxJ=idxI-1;
+      for(j=i;j<m_size;j++)
+	{
+	  if(m_Zarray[j]==1) continue;
+	  idxJ++;
+	  W[idxI][idxJ]=0.0;
+	  //  printf("Computing W: I=%d J=%d\n",idxI,idxJ);
+	  W[idxJ][idxI]=W[idxI][idxJ]=m_W[i][j];
+	}
+    }
+  /*
+  printf("Reduced W:\n");
+  for(i=0;i<newSize;i++)
+    {
+      for(j=0;j<newSize;j++) printf("%E ",W[i][j]);
+      printf("\n");
+    }
+  */
+  double* a=new double[newSize*newSize];
+  for(i=0;i<newSize;i++) for(j=0;j<newSize;j++) a[i+j*newSize]=W[i][j];
+  bool rc=this->invertMatrixNxN(a,newSize);
+  if(!rc)
+    {
+      delete[] a;
+      return NULL;
+    }
+  for(i=0;i<newSize;i++) for(j=0;j<newSize;j++) P[i][j]=a[i+j*newSize];
+  /*
+  printf("Inverted W:\n");
+  for(i=0;i<newSize;i++)
+    {
+      for(j=0;j<newSize;j++)
+	printf("%E ",P[i][j]);
+      printf("\n");
+    }
+  */
+  idxI=-1;
+
+  double Q[MAX_INP_SIZE];
+  memset(&Q[0],0,sizeof(Q));
+  for(i=0;i<m_size;i++)
+    {
+      if(m_Zarray[i]==1) continue;
+      idxI++;
+      Q[idxI]=0.0;
+      for(j=0;j<m_resSize;j++) Q[idxI]+=m_K[i][j]*m_R[j];
+    }
+  //printf("Solution:\n");
+  for(i=0;i<newSize;i++)
+    {
+      E[i]=0.0;
+      for(j=0;j<newSize;j++) E[i]+=P[i][j]*Q[j];
+      //  printf("%E \n",E[i]);
+    }
+  chi2=0.0;
+  for(i=0;i<newSize;i++)
+    for(j=0;j<newSize;j++) chi2+=E[i]*W[i][j]*E[j];
+  // printf("Significance: %f\n",chi2);
+  pLS = new LSMSolution(m_size);
+  pLS->m_Significance()=chi2;
+
+  idxI=-1;
+  for(i=0;i<m_size;i++)
+    {
+      if(m_Zarray[i]==1)
+	{
+	  (*pLS)[i]=0.0;pLS->m_fixVariable(i);
+	  continue;
+	}
+      idxI++;
+      (*pLS)[i]=E[idxI];idxJ=-1;
+      for(j=0;j<m_size;j++)
+	{
+	  if(m_Zarray[j]==1) continue;
+	  idxJ++;
+	  pLS->m_Cov(i,j)=P[idxI][idxJ];
+	}
+    }
+  delete[] a;
+  return pLS;
+}
+
+
+double TrigInDetBremDetectionTool::m_getCriterionValue(LSMSolution* pLS)
+{
+  double R[MAX_RES_SIZE];
+  int i,j,k;
+  double crit=0.0;
+
+  for(i=0;i<m_resSize;i++)
+    {
+      R[i]=m_R[i];
+      for(j=0;j<m_size;j++) R[i]-=m_A[i][j]*(*pLS)[j];
+    }
+  i=0;
+  for(std::vector<int>::iterator iIt=m_resSizes.begin();iIt!=m_resSizes.end();++iIt)
+      {
+	for(j=0;j<(*iIt);j++)
+	  {
+	    for(k=0;k<(*iIt);k++) crit+=R[i+j]*m_S[i+j][k]*R[i+k];
+	  }
+	i+=(*iIt);
+      }
+  return crit;
+}
+
+bool TrigInDetBremDetectionTool::m_checkFeasibility(LSMSolution * pS)
+{
+  int i;
+  bool rc=true;
+  for(i=0;i<m_size;i++)
+    {
+      if(m_Parray[i]!=1) continue;
+      if((*pS)[i]*m_sign<0.0) 
+	{
+	  rc=false;break;
+	}
+    }
+  return rc;
+}
+
+void TrigInDetBremDetectionTool::m_mixSolutions(LSMSolution* pST, LSMSolution* pLS)
+{
+  int i,iMin=-1;
+  double aMin=1000000.0,a;
+
+  for(i=0;i<m_size;i++)
+    {
+      if(m_Parray[i]!=1) continue;
+      if(m_sign*(*pST)[i]>0.0) continue;
+      a=(*pLS)[i]/((*pLS)[i]-(*pST)[i]);
+      //      printf("i=%d alpha=%f\n",i,a);
+      if(a<aMin)
+	{
+	  aMin=a;iMin=i;
+	}
+  }
+  if(iMin<0) return;
+  // printf("Closest component %d with alpha=%f\n",iMin,aMin);
+  for(i=0;i<m_size;i++)
+    {
+      (*pLS)[i]=(1.0-aMin)*(*pLS)[i]+aMin*(*pST)[i];
+    }
+  m_Zarray[iMin]=1;m_Parray[iMin]=0;
+}
+
+void TrigInDetBremDetectionTool::modifySurfaces(int flag)
+{
+  int i;
+
+  if(flag!=0)
+    {
+      if(m_pLS!=NULL)
+	{
+	  if(m_pLS->m_Significance()>m_SignificanceCut)
+	    {
+	      for(i=0;i<m_size;i++)
+		{
+		  if(!m_pLS->m_isOnConstraint(i))
+		    {
+		      m_surfArray[i]->m_setBreakPoint((*m_pLS)[i]);
+		      if(m_outputLevel<=MSG::DEBUG)
+			{
+			  m_log<<MSG::DEBUG<<i<<"  Breakpoint is set, u="<<(*m_pLS)[i]<<
+			    " X="<<m_jX[i]<<" Y="<<m_jY[i]<<" Z="<<m_jZ[i]<<endreq;
+			}
+		    }
+		  else 
+		    if(m_outputLevel<=MSG::DEBUG)
+			{
+			  m_log<<MSG::DEBUG<<i<<"  Not a Breakpoint X="<<m_jX[i]<<" Y="<<m_jY[i]<<
+			    " Z="<<m_jZ[i]<<endreq;
+			}
+		}
+	    }
+	}
+    }
+  else
+    {
+      for(i=0;i<m_size;i++) 
+	{
+	  m_surfArray[i]->m_unsetBreakPoint();                                                                               
+	}
+    }
+  delete m_pLS;m_pLS=NULL;
+}
+
+
+void TrigInDetBremDetectionTool::report(int flag)
+{
+  int i,j,k;
+
+  if(flag==1) //Residuals
+    {
+      m_log << MSG::DEBUG << "IDE Residuals : "<< endreq;
+      i=0;
+      for(std::vector<int>::iterator iIt=m_resSizes.begin();iIt!=m_resSizes.end();++iIt)
+	{
+	  for(j=0;j<(*iIt);j++)
+	    {
+	      m_log << MSG::DEBUG << "   "<<m_R[i]<< endreq;
+	      i++;
+	    }
+	}
+    }
+  if(flag==2) //LSM
+  {
+    i=0;
+    m_log << MSG::DEBUG << "LSM Problem : nU="<<m_lsmSize-1<<" nR="<<m_resSize<< endreq;
+    for(std::vector<int>::iterator iIt=m_resSizes.begin();iIt!=m_resSizes.end();++iIt)
+      {
+	for(j=0;j<(*iIt);j++)
+	  {
+	    m_log << MSG::DEBUG <<m_R[i]<<"    [";
+	    for(k=0;k<(*iIt);k++) m_log << MSG::DEBUG <<m_S[i][k]<<"  ";
+	    m_log << MSG::DEBUG <<"]  ";
+	    for(k=0;k<m_lsmSize-1;k++)
+	      m_log << MSG::DEBUG <<m_A[i][k]<<" ";
+	    m_log << MSG::DEBUG << endreq;
+	    i++;
+	  } 
+      }
+    m_log << MSG::DEBUG << "LSM Gain Matrix "<< endreq;
+    for(i=0;i<m_lsmSize-1;i++)
+      {
+	for(j=0;j<m_resSize;j++)
+	  m_log << MSG::DEBUG <<m_K[i][j]<<"  ";
+	m_log << MSG::DEBUG << endreq;
+      }
+    m_log << MSG::DEBUG << "LSM Weight Matrix "<< endreq;
+    for(i=0;i<m_lsmSize-1;i++)
+      {
+	for(j=0;j<m_lsmSize-1;j++)
+	  m_log << MSG::DEBUG <<m_W[i][j]<<"  ";
+	m_log << MSG::DEBUG << endreq;
+      }
+
+    m_log << MSG::DEBUG << "-----------------------"<< endreq;
+  }
+}
+
+
+LSMSolution::LSMSolution()
+{
+  m_size=0;
+  int i,j; 
+  m_Chi2=0.0;
+  for(i=0;i<=m_size;i++) 
+    {
+      m_u[i]=0.0;
+      m_fixedVariables[i]=0;
+      for(j=0;j<=m_size;j++) m_C[i][j]=0.0;
+    }
+}
+
+LSMSolution::~LSMSolution()
+{
+
+}
+
+LSMSolution::LSMSolution(int size) : m_size(size)
+{
+  int i,j; 
+  m_Chi2=0.0;
+  for(i=0;i<=m_size;i++) 
+    {
+      m_u[i]=0.0;
+      m_fixedVariables[i]=0;
+      for(j=0;j<=m_size;j++) m_C[i][j]=0.0;
+    }
+}
+
+double& LSMSolution::operator[] (int i)
+{
+  if((i<0)||(i>=m_size))
+    return m_u[0];
+  else return m_u[i];
+}
+
+double& LSMSolution::m_Cov(int i, int j)
+{
+  if((i<0)||(i>=m_size)) return m_C[0][0];
+  if((j<0)||(j>=m_size)) return m_C[0][0];
+  return m_C[i][j];
+}
+
+double& LSMSolution::m_Significance()
+{
+  return m_Chi2;
+}
+
+bool LSMSolution::m_isOnConstraint(int i)
+{
+  return (m_fixedVariables[i]==1);
+}
+
+void LSMSolution::m_fixVariable(int i)
+{
+  m_fixedVariables[i]=1;
+}
+
+void LSMSolution::m_report()
+{
+  int i,j;
+
+  printf("LSM Solution size %d\n",m_size);
+  for(i=0;i<m_size;i++)
+    {
+      printf("%E  ",m_u[i]);
+      if(m_isOnConstraint(i)) printf("constr.  ");
+      else printf("free    ");
+      for(j=0;j<m_size;j++) printf("%E ",m_C[i][j]);
+      printf("\n");
+    }
+  printf("Significance  %f\n",m_Chi2);
+  
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetCombinedTrackFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetCombinedTrackFitter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..86953b10a9515b6b30a50fb79926c20aed3ff460
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetCombinedTrackFitter.cxx
@@ -0,0 +1,252 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigInDetCombinedTrackFitter tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 15.06.2010 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+
+#include "GaudiKernel/ToolFactory.h"
+#include "StoreGate/DataHandle.h"
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetEvent/TrigInDetTrackCollection.h"
+
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetCombinedTrackFitter.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+TrigInDetCombinedTrackFitter::TrigInDetCombinedTrackFitter(const std::string& t, 
+							     const std::string& n,
+							     const IInterface*  p ): 
+  AthAlgTool(t,n,p),
+  m_doMultScatt(true),
+  m_doBremm(false),
+  m_momentumThreshold(10000.0),
+  m_highPtFitter("TrigL2HighPtTrackFitter"),
+  m_lowPtFitter("TrigL2LowPtTrackFitter"),
+  m_trackMaker("TrigDkfTrackMakerTool")
+{
+  declareInterface< ITrigInDetTrackFitter >( this ); 
+  declareProperty( "doMultScattering", m_doMultScatt = true);
+  declareProperty( "doBremmCorrection", m_doBremm=false);  
+  declareProperty( "HighPtTrackFitter", m_highPtFitter, "TrigL2HighPtTrackFitter");
+  declareProperty( "LowPtTrackFitter", m_lowPtFitter, "TrigL2LowPtTrackFitter");
+  declareProperty( "MomentumThreshold",m_momentumThreshold=10000.0);  
+  declareProperty( "Chi2Cut", m_DChi2 = 1000.0);
+}
+
+StatusCode TrigInDetCombinedTrackFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  sc=m_trackMaker.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve "<<m_trackMaker);
+      return sc;
+    }
+  sc=m_highPtFitter.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve "<<m_highPtFitter);
+      return sc;
+    }
+  sc=m_lowPtFitter.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve "<<m_lowPtFitter);
+      return sc;
+    }
+  ATH_MSG_INFO("TrigInDetCombinedTrackFitter initialized ");
+  return sc;
+}
+
+StatusCode TrigInDetCombinedTrackFitter::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+
+void TrigInDetCombinedTrackFitter::fit(TrigInDetTrackCollection* recoTracks )
+{
+  double Rk[5], Phi0, D0, Z0, Eta, errD0, errZ0, errEta, errPhi0, errPt;
+  double CV[5][5],a,b,c,Theta;
+  std::vector<double>* pCov;
+  TrigInDetTrackCollection::iterator trIt,lastIt;
+
+  std::vector<Trk::TrkBaseNode*> vpTrkNodes;
+
+  trIt = recoTracks->begin();lastIt = recoTracks->end();
+  for(; trIt !=lastIt; trIt++) 
+    {
+      TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>((*trIt)->param());
+      if(param==NULL)
+	{
+    ATH_MSG_WARNING("Fit Failed -- TrigInDetTrack has no parameters");
+	  continue;
+	}
+      if(fabs(param->pT())<100.0)
+	{
+    ATH_MSG_DEBUG("Estimated Pt is too low "<<param->pT()<<" - skipping fit");
+	  continue;
+	}
+      
+      // 1. Create filtering nodes
+
+      bool trackResult = m_trackMaker->createDkfTrack(*(*trIt)->siSpacePoints(),vpTrkNodes, m_DChi2);
+      if(!trackResult) continue;
+
+      int nHits=vpTrkNodes.size();
+
+			ATH_MSG_DEBUG(nHits<<" filtering nodes created");
+
+      // 2. Create initial track state:
+
+      double chi2tot=0.0;
+      int ndoftot=-5;
+
+      Rk[0]=param->a0();
+      Rk[1]=param->z0();
+      Rk[2]=param->phi0();
+      Theta=2.0*atan(exp(-param->eta()));
+      Rk[3]=Theta;
+      Rk[4]=sin(Theta)/param->pT();
+      double Momentum = 1/Rk[4];
+
+      Trk::TrkTrackState* pTS = new Trk::TrkTrackState(Rk);
+      double Gk[5][5];
+      memset(&Gk[0][0],0,sizeof(Gk));
+      Gk[0][0]=100.0;Gk[1][1]=1000.0;Gk[2][2]=0.01;Gk[3][3]=0.01;Gk[4][4]=1e-6;
+      pTS->m_setTrackCovariance(Gk);
+      if(m_doMultScatt)  
+	pTS->m_setScatteringMode(1);
+      if(m_doBremm)
+	pTS->m_setScatteringMode(2);
+
+			ATH_MSG_DEBUG("Initial params: locT="<<Rk[0]<<" locL="<<Rk[1]<<" phi="<<Rk[2]
+		  <<" theta="<<Rk[3]<<" Q="<<Rk[4]<<" pT="<<sin(Rk[3])/Rk[4]);
+
+      // 3. Call appropriate fitter
+        
+      if(fabs(Momentum)<m_momentumThreshold)
+	{
+	  pTS = m_lowPtFitter->fit(pTS,vpTrkNodes,true);
+	}
+      else
+	{
+	  pTS = m_highPtFitter->fit(pTS,vpTrkNodes,true);
+	}
+      
+      //pTS = m_lowPtFitter->fit(pTS,vpTrkNodes);
+      std::vector<Trk::TrkBaseNode*>::iterator pnIt(vpTrkNodes.begin()),
+	pnEnd(vpTrkNodes.end());
+      if(pTS!=NULL)
+	{
+	  
+	  for(;pnIt!=pnEnd;++pnIt)
+	    {
+				ATH_MSG_DEBUG("dChi2="<<(*pnIt)->m_getChi2());
+	      if((*pnIt)->m_isValidated())
+		{
+		  chi2tot+=(*pnIt)->m_getChi2();
+		  ndoftot+=(*pnIt)->m_getNdof();
+		}
+	    }
+	  double Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	  Phi0 = pTS->m_getTrackState(2);
+	  if(Phi0>M_PI) Phi0-=2*M_PI;
+	  if(Phi0<-M_PI) Phi0+=2*M_PI;
+	  Eta = -log(sin(0.5*pTS->m_getTrackState(3))/cos(0.5*pTS->m_getTrackState(3)));
+	  Z0 = pTS->m_getTrackState(1);
+	  D0 = pTS->m_getTrackState(0);
+
+	  errD0 = sqrt(pTS->m_getTrackCovariance(0,0));
+	  errZ0 = sqrt(pTS->m_getTrackCovariance(1,1));
+	  errPhi0 = sqrt(pTS->m_getTrackCovariance(2,2));
+	  errEta = sqrt(pTS->m_getTrackCovariance(3,3))/fabs(sin(pTS->m_getTrackState(3)));
+	  b=cos(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	  c=-Pt/pTS->m_getTrackState(4);
+	  a=-1.0/sin(pTS->m_getTrackState(3));
+	  errPt = sqrt(b*b*(pTS->m_getTrackCovariance(3,3))+c*c*(pTS->m_getTrackCovariance(4,4))+
+		       2.0*b*c*(pTS->m_getTrackCovariance(3,4)));
+	  
+	  pCov=new std::vector<double>;
+      
+	  CV[0][0]=pTS->m_getTrackCovariance(0,0);
+	  CV[0][1]=pTS->m_getTrackCovariance(0,2);
+	  CV[0][2]=pTS->m_getTrackCovariance(0,1);
+	  CV[0][3]=a*(pTS->m_getTrackCovariance(0,3));
+	  CV[0][4]=b*(pTS->m_getTrackCovariance(0,3))+c*(pTS->m_getTrackCovariance(0,4));
+	  CV[1][1]=pTS->m_getTrackCovariance(2,2);
+	  
+	  CV[1][2]=pTS->m_getTrackCovariance(1,2);
+	  CV[1][3]=a*(pTS->m_getTrackCovariance(2,3));
+	  CV[1][4]=b*(pTS->m_getTrackCovariance(2,3))+c*(pTS->m_getTrackCovariance(2,4));
+	  CV[2][2]=pTS->m_getTrackCovariance(1,1);
+	  CV[2][3]=a*(pTS->m_getTrackCovariance(1,3));
+	  CV[2][4]=b*(pTS->m_getTrackCovariance(1,3))+c*(pTS->m_getTrackCovariance(1,4));
+	  CV[3][3]=a*a*(pTS->m_getTrackCovariance(3,3));
+	  CV[3][4]=a*(b*(pTS->m_getTrackCovariance(3,3))+c*(pTS->m_getTrackCovariance(3,4)));
+	  CV[4][4]=b*b*(pTS->m_getTrackCovariance(3,3))+2.0*b*c*(pTS->m_getTrackCovariance(3,4))+
+	    c*c*(pTS->m_getTrackCovariance(4,4));
+
+	  for(int i=0;i<5;i++)
+	    for(int j=i;j<5;j++) pCov->push_back(CV[i][j]);
+
+	  const TrigInDetTrackFitPar* tidtfp = new TrigInDetTrackFitPar(D0,Phi0,Z0,Eta, Pt,
+									errD0,errPhi0,errZ0,
+									errEta,errPt,pCov);
+	  delete pTS;
+            
+		ATH_MSG_DEBUG("Total chi2 ="<<chi2tot<<" NDOF="<<ndoftot);
+		ATH_MSG_DEBUG("Fitted parameters: d0="<<D0<<" phi0="<<Phi0<<" z0="<<Z0	
+				<<" eta0="<<Eta<<" pt="<<Pt);
+	 
+	  if((ndoftot<0) || (fabs(Pt)<100.0) || (std::isnan(Pt)))
+	    {
+				ATH_MSG_DEBUG("Fit failed - possibly floating point problem");
+	      delete tidtfp;
+	      (*trIt)->chi2(1e8);
+	    }
+	  else
+	    {
+	      delete param;
+	      (*trIt)->param(tidtfp);
+	      if(ndoftot>1) chi2tot/=ndoftot;
+	      (*trIt)->chi2(chi2tot);
+	    }
+	}
+      else
+	{
+	  ATH_MSG_DEBUG("Track fitter failure ");
+	  (*trIt)->chi2(1e8);
+	}
+
+      pnIt=vpTrkNodes.begin();pnEnd=vpTrkNodes.end();
+      for(;pnIt!=pnEnd;++pnIt) 
+	{
+	  delete((*pnIt)->m_getSurface());
+	  delete (*pnIt);
+	}
+      vpTrkNodes.clear();
+    }
+}
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetKarimakiFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetKarimakiFitter.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..eaf8e04c52cb675b458c8413aa111148831a7d68
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetKarimakiFitter.cxx
@@ -0,0 +1,404 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigInDetKarimakiFitter tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 13.02.2007 Package created
+//
+// Author: Carlo Schiavi, Genova
+// e-mail: Carlo.Schiavi@ge.infn.it
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+
+#include "StoreGate/StoreGateSvc.h" 
+
+#include "GaudiKernel/ToolFactory.h"
+#include "StoreGate/DataHandle.h"
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetEvent/TrigInDetTrackCollection.h"
+
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "InDetPrepRawData/SCT_Cluster.h"
+#include "InDetPrepRawData/PixelCluster.h"
+#include "TrigTimeAlgs/TrigTimerSvc.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetKarimakiFitter.h"
+
+
+
+/*********************************************************************************/
+/** Constructor                                                                 **/
+/*********************************************************************************/
+TrigInDetKarimakiFitter::TrigInDetKarimakiFitter(const std::string& t, 
+						 const std::string& n,
+						 const IInterface* p ) : AthAlgTool(t,n,p) {
+  
+  // Declare interface
+  declareInterface< ITrigInDetTrackFitter >( this );
+
+  // Declare properties
+  //declareProperty( "Chi2Cut", m_DChi2 = 1000.0);
+}
+
+
+/*********************************************************************************/
+/** Destructor                                                                  **/
+/*********************************************************************************/
+TrigInDetKarimakiFitter::~TrigInDetKarimakiFitter() {
+}
+
+
+/*********************************************************************************/
+/** initialize                                                                  **/
+/*********************************************************************************/
+StatusCode TrigInDetKarimakiFitter::initialize() {
+
+  // Base init and get message svc
+  m_log = new MsgStream(msgSvc(), name());
+  StatusCode sc = AthAlgTool::initialize();
+  if(sc.isFailure()) {
+    (*m_log) << MSG::FATAL << "unable to initialize" << endreq;
+    return StatusCode::FAILURE;
+  }
+ 
+  // Retrieve Detector Description
+  StoreGateSvc* detectorStore;
+  sc = service("DetectorStore", detectorStore);
+  if(sc.isFailure()) {
+    (*m_log) << MSG::FATAL << "unable to locate Detector Store" << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  // Get SCT & pixel Identifier helpers
+  if (detectorStore->retrieve(m_pixelId, "PixelID").isFailure()) { 
+     (*m_log) << MSG::FATAL << "Could not get Pixel ID helper" << endreq;
+     return StatusCode::FAILURE; 
+  }
+                                                                                                                                           
+  if (detectorStore->retrieve(m_sctId, "SCT_ID").isFailure()) {
+     (*m_log) << MSG::FATAL << "Could not get SCT ID helper" << endreq;
+     return StatusCode::FAILURE;
+  }
+  
+  (*m_log) << MSG::INFO << "TrigInDetKarimakiFitter constructed" << endreq;
+  return sc;
+}
+
+
+/*********************************************************************************/
+/** finalize                                                                    **/
+/*********************************************************************************/
+StatusCode TrigInDetKarimakiFitter::finalize() {
+
+  // Destroy message svc
+  delete m_log;
+
+  // Base finalize
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+
+/*********************************************************************************/
+/** fit                                                                         **/
+/*********************************************************************************/
+void TrigInDetKarimakiFitter::fit(TrigInDetTrackCollection* tracks) {
+
+  // Loop on tracks
+  TrigInDetTrackCollection::iterator t, tEnd=tracks->end();
+  for(t=tracks->begin(); t!=tEnd; t++) {
+    
+    // Ancillary track
+    TrigInDetKarimakiFitter::AncillaryTrack at;
+    
+    // Perform three point fit
+    if((*t)->siSpacePoints()->size()>2) {
+      circlefitRPhi(*t, at);
+      fitRZ(*t, at);
+    }
+
+    // Perform full fit
+    if((*t)->siSpacePoints()->size()>3) {
+      fitRPhi(*t, at);
+    }
+    
+    // Evaluate final chi2 value  
+    (*t)->chi2(sqrt(at.chi2rz*at.chi2rz + at.chi2rp*at.chi2rp));
+  }
+}
+
+
+/*********************************************************************************/
+/** circlefitRPhi                                                               **/
+/*********************************************************************************/
+void TrigInDetKarimakiFitter::circlefitRPhi(TrigInDetTrack* t, TrigInDetKarimakiFitter::AncillaryTrack& at) {
+  
+  /** Fitting variables. **/
+  double phi=0, d0=0;
+  double x[3], y[3];
+  double tr, cx1, cy1, cx2, cy2, xm1, ym1, xm2, ym2;
+  double phi0, dph0p;
+
+  /** Get space point indexes. **/
+  double rsp, rval[3]={10000.0, 10000.0, 10000.0};
+  int ind, rind[3]={0, 1, 2};
+
+  std::vector<const TrigSiSpacePoint*>::iterator sp, spEnd=t->siSpacePoints()->end();
+  for(sp=t->siSpacePoints()->begin(), ind=0; sp!=spEnd; sp++, ind++) {
+    // Save indices for preliminary RPhi fit
+    rsp = (*sp)->r();
+    if(rsp<rval[0])                          {rval[0]=rsp; rind[0]=ind;}
+    if(rsp>122.5 && (rsp-122.5)<rval[1])     {rval[1]=rsp-122.5; rind[1]=ind;}
+    if(rsp>350.0 && (rsp-350.0)<rval[2])     {rval[2]=rsp-350.5; rind[2]=ind;}
+  }
+  if(rind[0]==rind[1] || rind[1]==rind[2]) {rind[0]=0; rind[1]=1; rind[2]=t->siSpacePoints()->size()-1;}
+
+  /** Get space point coordinates. */
+  for(int i=0; i<3; i++) {
+    x[i] = (*(t->siSpacePoints()))[rind[i]]->x();
+    y[i] = (*(t->siSpacePoints()))[rind[i]]->y();
+  }
+
+  /** Evaluate useful quantities. */
+  xm1 = (x[1]+x[0])/2;
+  ym1 = (y[1]+y[0])/2;
+  cx1 = y[1] - y[0];
+  cy1 = x[0] - x[1];
+	
+  xm2 = (x[1]+x[2])/2;
+  ym2 = (y[1]+y[2])/2;
+  cx2 = y[1] - y[2];
+  cy2 = x[2] - x[1];
+	
+  /** Check if track is too straight. */
+  bool straight=false;
+  if(cy1/cx1 == cy2/cx2) {
+    straight=true;
+  }
+  else {
+    // Evaluate circle radius
+    tr = (xm2-xm1+(ym1-ym2)*cx2/cy2)/(cx1-cy1*cx2/cy2);
+    at.xc = xm1 + cx1*tr;
+    at.yc = ym1 + cy1*tr;
+    at.rc = sqrt((at.xc-x[0])*(at.xc-x[0])+(at.yc-y[0])*(at.yc-y[0]));
+    at.pt = at.rc*1.042*9.0/15.0;
+    if(at.pt>=1000000.0) straight=true;
+  }
+
+  /** Treat straight tracks. */
+  if(straight) {
+    phi = atan2(y[1]-y[0], x[1]-x[0]);
+    if(phi<-M_PI) phi+=2*M_PI;
+    if(phi>M_PI)  phi-=2*M_PI;
+    at.pt = 1000000.0;
+    at.xc = at.yc = at.rc = 0;
+    double phiV = atan2(y[0], x[0]);
+    d0 = sqrt(x[0]*x[0]+y[0]*y[0])*sin(phiV-phi);
+  } 
+  /** Treat curved tracks. */
+  else {
+    at.phic = atan2(at.xc, -at.yc);
+    d0 = sqrt(at.xc*at.xc+at.yc*at.yc)-at.rc;
+    /** Evaluate charge. */
+    phi0 = atan2(at.xc-x[0],-at.yc+y[0]);
+    dph0p = phi0-at.phic;
+    if (dph0p >  M_PI) dph0p = dph0p - 2*M_PI;
+    if (dph0p < -M_PI) dph0p = dph0p + 2*M_PI;
+    if (dph0p > 0) {
+      at.q = -1;
+    } else {
+      at.q = 1;
+    }
+    at.pt = at.pt*at.q;
+      
+    /** Evaluate phi0. */
+    phi = atan2(-at.xc, at.yc) + (1+at.q)/2*M_PI;
+    if(phi<-M_PI) phi+=2*M_PI;
+    if(phi>M_PI)  phi-=2*M_PI;
+    
+    /** Evaluate d0 sign. */
+    double absd0  = fabs(d0);
+    double phiV = atan2(y[0], x[0]);
+    if(phiV<-M_PI) phiV+=2*M_PI;
+    if(phiV> M_PI) phiV-=2*M_PI;
+    float newsign = sin(phiV-phi);
+    if (newsign<0){
+      d0 = -absd0;
+    } else {
+      d0 =  absd0;
+    }    
+  }
+    
+  /** Save track parameters. */
+  TrigInDetTrackFitPar* par = const_cast<TrigInDetTrackFitPar*>(t->param()); 
+  par->a0(d0);
+  par->phi0(phi);
+  par->pT(at.pt);
+
+  /** Save chi square value . */
+  at.nSP = 3;
+  at.chi2rp = 0;
+}
+
+
+
+/*********************************************************************************/
+/*********************************************************************************/
+/** fitRZ                                                                       **/
+/*********************************************************************************/
+/*********************************************************************************/
+void TrigInDetKarimakiFitter::fitRZ(TrigInDetTrack* t, TrigInDetKarimakiFitter::AncillaryTrack& at) {
+	
+  /** Fill sum variables. */
+
+  // Sum variable
+  double n=0, rr=0, rz=0, r=0, z=0;
+  double iphi, ir, iz, ezez;
+
+  // Preliminary track parameters
+  TrigInDetTrackFitPar* par = const_cast<TrigInDetTrackFitPar*>(t->param()); 
+  double z1=(*(t->siSpacePoints()))[0]->z(), z2=(*(t->siSpacePoints()))[1]->z();
+  double r1=(*(t->siSpacePoints()))[0]->r(), r2=(*(t->siSpacePoints()))[1]->r();
+  at.cotantheta = (z2-z1)/(r2-r1);
+
+  // Loop on SPs
+  std::vector<const TrigSiSpacePoint*>::iterator sp, spEnd=t->siSpacePoints()->end();
+  for(sp=t->siSpacePoints()->begin(); sp!=spEnd; sp++) {
+    // Evaluate error on Z
+    ezez = ((*sp)->dz()*(*sp)->dz()) + (at.cotantheta*at.cotantheta)*((*sp)->dr()*(*sp)->dr());
+    // Evaluate sum variables
+    iphi = atan2(at.xc-(*sp)->x(), -at.yc+(*sp)->y());
+    ir = iphi-at.phic; if(ir>M_PI) ir=ir-2*M_PI; if(ir<-M_PI) ir=ir+2*M_PI;
+    iz = (*sp)->z();
+    n+=1/ezez; rr+=(ir*ir)/ezez; rz+=(ir*iz)/ezez; r+=ir/ezez; z+=iz/ezez;
+  }
+
+
+  /** Evaluate line parameters. */
+  double invdelta, z0;
+  invdelta = 1/(n*rr-r*r);
+  z0       = invdelta*(rr*z-r*rz);
+  at.ang = invdelta*(n*rz-r*z);
+
+
+  /** Evaluate track parameters. */
+  double theta = atan2(-at.q*at.rc, at.ang);
+  if(theta<0) theta = theta + (1+at.q)/2*M_PI;
+  par->eta(-log(tan(theta/2)));
+  par->z0(z0);
+
+
+  /** Evaluate chi square. */
+  at.cotantheta = 1/tan(theta);
+  double chi2 = 0;
+  for(sp=t->siSpacePoints()->begin(); sp!=spEnd; sp++) {
+    // Evaluate error on Z
+    ezez = ((*sp)->dz()*(*sp)->dz()) + (at.cotantheta*at.cotantheta)*((*sp)->dr()*(*sp)->dr());
+    // Evaluate sum variables
+    iphi = atan2(at.xc-(*sp)->x(), -at.yc+(*sp)->y());
+    ir = iphi-at.phic; if(ir>M_PI) ir=ir-2*M_PI; if(ir<-M_PI) ir=ir+2*M_PI;
+    iz = (*sp)->z();
+    double izgood = z0 + at.ang*ir;
+    chi2+=(iz-izgood)*(iz-izgood)/ezez;
+  }
+
+  /* Save chi square value. */
+  at.chi2rz = chi2;
+  at.nSP = t->siSpacePoints()->size();
+}
+
+
+
+/*********************************************************************************/
+/*********************************************************************************/
+/** fitRPhi                                                                     **/
+/*********************************************************************************/
+/*********************************************************************************/
+void TrigInDetKarimakiFitter::fitRPhi(TrigInDetTrack* t, TrigInDetKarimakiFitter::AncillaryTrack& at) {
+
+  /** Fill sum variables. */
+  // Sum variable
+  double Cxx, Cxy, Cyy, Cxrr, Cyrr, Crrrr, q1, q2;
+  double Sw=0, x=0, y=0, xx=0, xy=0, yy=0, xrr=0, yrr=0, rr=0, rrrr=0;
+  double ix, iy, ir, iphi, iphic, ee;
+  double phi, rho, d0;
+
+  // Preliminary track parameters
+  TrigInDetTrackFitPar* par = const_cast<TrigInDetTrackFitPar*>(t->param()); 
+  phi = par->phi0();
+
+  // Loop on SPs
+  std::vector<const TrigSiSpacePoint*>::iterator sp, spEnd=t->siSpacePoints()->end();
+  for(sp=t->siSpacePoints()->begin(); sp!=spEnd; sp++) {
+    // Get coordinates
+    ix = (*sp)->x();
+    iy = (*sp)->y();
+    ir = (*sp)->r();
+    iphi = (*sp)->phi();
+    iphic = atan2(iy-at.yc, ix-at.xc);
+    // Evaluate error
+    ee = (ir*ir*(*sp)->dphi()*(*sp)->dphi()*cos(M_PI/2+iphi-iphic)*cos(M_PI/2+iphi-iphic)) +
+         ((*sp)->dr()*(*sp)->dr()*sin(M_PI/2+iphi-iphic)*sin(M_PI/2+iphi-iphic));
+    // Evaluate sum variables
+    Sw+=1/ee; x+=ix/ee; y+=iy/ee; xx+=(ix*ix)/ee; xy+=(ix*iy)/ee; yy+=(iy*iy)/ee; xrr+=(ix*ir*ir)/ee; yrr+=(iy*ir*ir)/ee; rr+=(ir*ir)/ee; rrrr+=(ir*ir*ir*ir)/ee;
+  }
+  // Divide by weight sum
+  x/=Sw; y/=Sw; xx/=Sw; xy/=Sw; yy/=Sw; xrr/=Sw; yrr/=Sw; rr/=Sw; rrrr/=Sw;
+
+
+  /** Evaluate circle parameters. */
+  Cxx=xx-x*x; Cxy=xy-x*y; Cyy=yy-y*y; Cxrr=xrr-x*rr; Cyrr=yrr-y*rr; Crrrr=rrrr-rr*rr;
+  q1=(Crrrr*Cxy)-(Cxrr*Cyrr); q2=Crrrr*(Cxx-Cyy)-(Cxrr*Cxrr)+(Cyrr*Cyrr);
+
+  double signx = cos(phi)/fabs(cos(phi)); double signy = sin(phi)/fabs(sin(phi));
+
+  phi = 0.5*atan2(signy*2*q1/q2, signx);
+  if(phi>M_PI) phi-=2*M_PI; else if(phi<-M_PI) phi+=2*M_PI;
+
+  if(signx<0 && signy>=0) {
+    if(phi<0) phi=M_PI/2-phi;
+    else phi=M_PI-phi;
+  }
+  else if(signx>=0 && signy<0) {
+    if(phi<0) phi=3*M_PI/2-phi;
+    else phi=-phi;
+  }
+  else if(signx>=0 && signy>=0) {
+    if(phi<0) phi=M_PI/2+phi;
+    else phi=phi;
+  }
+  else if(signx<0 && signy<0) {
+    if(phi<0) phi=3*M_PI/2+phi;
+    else phi=M_PI+phi;
+  }
+  if(phi>M_PI) phi-=2*M_PI; else if(phi<-M_PI) phi+=2*M_PI;
+
+  at.k     = (sin(phi)*Cxrr-cos(phi)*Cyrr)/Crrrr; 
+  at.delta = -at.k*rr + sin(phi)*x - cos(phi)*y;
+  rho        = 2*at.k/sqrt(1-4*at.delta*at.k);
+  d0         = -2*at.delta/(1+sqrt(1-4*at.delta*at.k));
+
+  /** Evaluate track parameters. */
+  par->phi0(phi);
+  par->a0(d0);
+  par->pT(1.042*(1/rho)*9.0/15.0);
+
+
+  /** Evaluate chi square. */
+  double chi2 = Sw*(1+rho*d0)*(1+rho*d0)*(sin(phi)*sin(phi)*Cxx - 2*sin(phi)*cos(phi)*Cxy + cos(phi)*cos(phi)*Cyy - at.k*at.k*Crrrr);
+
+  /* Save chi square value. */
+  at.chi2rp = chi2;
+  at.nSP = t->siSpacePoints()->size();
+}	
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetOfflineTrackFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetOfflineTrackFitter.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..155ffb931e46eaca0817b4f4e1c5325b91b374dc
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetOfflineTrackFitter.cxx
@@ -0,0 +1,325 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigInDetOfflineTrackFitter tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 08.05.2010 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+
+#include "StoreGate/StoreGateSvc.h" 
+#include "GaudiKernel/ToolFactory.h"
+#include "StoreGate/DataHandle.h"
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetEvent/TrigInDetTrackCollection.h"
+
+#include "TrkTrack/TrackCollection.h"
+
+#include "InDetPrepRawData/SCT_Cluster.h"
+#include "InDetPrepRawData/PixelCluster.h"
+#include "TrigTimeAlgs/TrigTimerSvc.h"
+#include "TrkParameters/TrackParameters.h"
+#include "TrkEventPrimitives/FitQuality.h"
+#include "TrkEventPrimitives/ParamDefs.h"
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetOfflineTrackFitter.h"
+
+TrigInDetOfflineTrackFitter::TrigInDetOfflineTrackFitter(const std::string& t, 
+					   const std::string& n,
+					   const IInterface*  p ): 
+  AthAlgTool(t,n,p),
+  m_trackFitter("Trk::GlobalChi2Fitter/InDetTrigTrackFitter")
+{
+  declareInterface< ITrigInDetTrackFitter >( this );
+
+  declareProperty( "doMultScattering", m_doMultScatt = true);
+  declareProperty( "doBremmCorrection", m_doBremm=false);  
+  declareProperty( "Chi2Cut", m_DChi2 = 1000.0);
+  declareProperty( "OfflineClusters", m_offlineClusters = true);
+  declareProperty("OfflineTrackFitter", m_trackFitter);
+}
+
+StatusCode TrigInDetOfflineTrackFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  StoreGateSvc* detStore;
+  sc = service("DetectorStore", detStore);
+  if ( sc.isFailure() ) { 
+    ATH_MSG_FATAL("DetStore service not found"); 
+    return StatusCode::FAILURE; 
+  }
+  
+  sc=m_trackFitter.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve "<<m_trackFitter);
+      return sc;
+    }
+  
+  /*
+  StatusCode scFit = toolSvc->retrieveTool(m_FitterName, m_FitterInstance, m_trackFitter);
+  if (scFit.isFailure())
+    {
+      athenaLog<<MSG::ERROR<<"Could not find refit tool of type "<<m_FitterName<<". Exiting."<< endreq;
+      return scFit;
+    }
+  else 
+    {
+      athenaLog << MSG::INFO << "Refit tool \""<<m_FitterName<<" "<<m_FitterInstance<<"\" booked."<< endreq;
+    }
+  */
+  if (detStore->retrieve(m_pixelId, "PixelID").isFailure()) {
+    ATH_MSG_FATAL("Could not get Pixel ID helper");
+    return StatusCode::FAILURE;
+  }
+
+  if (detStore->retrieve(m_sctId, "SCT_ID").isFailure()) {
+    ATH_MSG_FATAL("Could not get SCT ID helper");
+    return StatusCode::FAILURE;
+  }
+   
+  ITrigTimerSvc* timerSvc;
+  StatusCode scTime = service( "TrigTimerSvc", timerSvc);
+  if( scTime.isFailure() ) {
+    ATH_MSG_INFO("Unable to locate Service TrigTimerSvc ");
+    m_timers = false;
+  } 
+  else{
+    m_timers = true;  
+  }
+//   add some timers:
+//
+  if ( m_timers ) {
+    m_timer[0] = timerSvc->addItem("TrigToOffline");
+    m_timer[1] = timerSvc->addItem("OfflineFit");
+    m_timer[2] = timerSvc->addItem("OfflineToTrig");
+  }
+  ATH_MSG_INFO("TrigInDetOflineTrackFitter constructed ");
+  return sc;
+}
+
+StatusCode TrigInDetOfflineTrackFitter::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+void TrigInDetOfflineTrackFitter::fit(TrigInDetTrackCollection* recoTracks )
+{
+  double Pt, Phi0, D0, Z0, Eta, errD0, errZ0, errEta, errPhi0, errPt,a,b,c;
+  double CV[5][5],Theta;
+  std::vector<double>* pCov;
+  TrigInDetTrackCollection::iterator trIt,lastIt;
+
+  if(m_timers)
+    {
+      m_timer[0]->start();
+      m_timer[0]->pause();
+      m_timer[1]->start();
+      m_timer[1]->pause();
+      m_timer[2]->start();
+      m_timer[2]->pause();
+    }
+
+  trIt = recoTracks->begin();lastIt = recoTracks->end();
+  for(; trIt !=lastIt; trIt++) 
+    {
+      TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>((*trIt)->param());
+      if(param==NULL)
+	{
+    ATH_MSG_WARNING("Fit Failed -- TrigInDetTrack has no parameters");
+	  continue;
+	}
+      Pt=param->pT();
+      if(fabs(Pt)<100.0)
+	{
+		ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+	  continue;
+	}
+      if (!(*trIt)->siSpacePoints())
+	{
+		ATH_MSG_DEBUG("Track has no spacepoints - skipping fit");
+	  continue;
+	}
+
+      // 1. TrigInDetTrack -> TrkTrack
+      if ( m_timers ) m_timer[0]->resume();
+      Phi0=param->phi0();
+      Theta=2.0*atan(exp(-param->eta()));	
+      AmgSymMatrix(5)* pM = new AmgSymMatrix(5);
+      pM->setZero();
+      (*pM)(0,0)=100.0;
+      (*pM)(1,1)=100.0;
+      (*pM)(2,2)=0.01;
+      (*pM)(3,3)=0.01;
+      (*pM)(4,4)=1e-6;
+      const Trk::PerigeeSurface   perSurf;
+      const Trk::Perigee* pMP = new Trk::Perigee(param->a0(),param->z0(),Phi0,Theta,sin(Theta)/Pt,perSurf, pM);
+
+      Trk::PrepRawDataSet prepRDColl;
+
+      std::vector<const TrigSiSpacePoint*>::iterator pSP=(*trIt)->siSpacePoints()->begin();
+      std::vector<const TrigSiSpacePoint*>::iterator lastSP=(*trIt)->siSpacePoints()->end();
+      for(int iSP=0; pSP != lastSP; pSP++, iSP++)
+	{
+	  if (m_sctId->is_sct((*pSP)->identify()))
+	    {
+	      for (int iClusInSP=0; iClusInSP<2; iClusInSP++)
+		{
+		  const InDet::SCT_Cluster* pCL;
+		  if (iClusInSP == 1)
+		    pCL = dynamic_cast<const InDet::SCT_Cluster*>((*pSP)->clusters().first);
+		  else                     
+		    pCL = dynamic_cast<const InDet::SCT_Cluster*>((*pSP)->clusters().second);
+		  if(!pCL) continue;
+		  /*
+		  const Trk::LocalParameters*  loc = new Trk::LocalParameters(pCL->localPosition());
+		  const Trk::GlobalPosition  glo(pCL->globalPosition());
+		  const Trk::ErrorMatrix*    err = new Trk::ErrorMatrix(pCL->localErrorMatrix ());
+		  const IdentifierHash idHash = m_sctId->wafer_hash(m_sctId->wafer_id(pCL->identify()));
+		  InDet::SCT_ClusterOnTrack* pSC=new InDet::SCT_ClusterOnTrack(pCL,loc,err,idHash,glo);
+		  */
+		  prepRDColl.push_back(pCL);	                            
+		}
+	    }
+	  else 
+	    {  // Pixel spacepoint
+	      const InDet::PixelCluster* pCL = dynamic_cast<const InDet::PixelCluster*>((*pSP)->clusters().first);
+	      if(!pCL) continue;
+	      /*
+	      const Trk::LocalParameters*  loc = new Trk::LocalParameters(pCL->localPosition());
+	      const Trk::GlobalPosition  glo(pCL->globalPosition());
+	      const Trk::ErrorMatrix*    err = new Trk::ErrorMatrix(pCL->localErrorMatrix ());
+	      const IdentifierHash idHash = m_pixelId->wafer_hash(m_pixelId->wafer_id(pCL->identify()));
+	      InDet::PixelClusterOnTrack* pSC=new InDet::PixelClusterOnTrack(pCL,loc,err,idHash,glo,
+									     pCL->gangedPixel());
+	      */
+	      prepRDColl.push_back(pCL);
+	    }
+	}
+      if ( m_timers ) m_timer[0]->pause();
+      if ( m_timers ) m_timer[1]->resume();
+
+      Trk::Track* newtrack = m_trackFitter->fit(prepRDColl,*pMP,false,Trk::pion);
+
+      if ( m_timers ) m_timer[1]->pause();
+      if ( m_timers ) m_timer[2]->resume();
+
+      delete pMP;
+
+      bool badFit=false;
+      if(newtrack!=NULL)
+	{
+	  const Trk::Perigee *aMeasPer = newtrack->perigeeParameters();
+	  if (aMeasPer==nullptr)
+	    {
+	      ATH_MSG_DEBUG("Could not get Trk::MeasuredPerigee");
+	      badFit=true;
+	    }
+	  else
+	    {
+	      D0 = aMeasPer->parameters()[Trk::d0];
+	      Z0 = aMeasPer->parameters()[Trk::z0];
+	      Phi0 = aMeasPer->parameters()[Trk::phi0];
+	      Theta = aMeasPer->parameters()[Trk::theta];
+	      if(Phi0>M_PI) Phi0-=2*M_PI;
+	      if(Phi0<-M_PI) Phi0+=2*M_PI;
+	      Eta = -log(sin(0.5*Theta)/cos(0.5*Theta));
+
+	      double qOverP = aMeasPer->parameters()[Trk::qOverP];
+	      Pt=sin(Theta)/qOverP;
+				ATH_MSG_DEBUG("Refitted offline parameters " << D0  << " " << Z0  << " " 
+					<< Phi0 << " " << Eta << " " << Pt);
+
+	      double Gk[5][5];
+
+	      for(int i=0;i<5;i++) 
+		for(int j=0;j<5;j++)
+		  Gk[i][j]=(*aMeasPer->covariance())(i,j);
+
+	      errD0 = sqrt(Gk[0][0]);
+	      errZ0 = sqrt(Gk[1][1]);
+	      errPhi0 = sqrt(Gk[2][2]);
+	      errEta = sqrt(Gk[3][3])/fabs(sin(Theta));
+	      b=cos(Theta)/qOverP;
+	      c=-Pt/qOverP;
+	      a=-1.0/sin(Theta);
+	      errPt = sqrt(b*b*(Gk[3][3])+c*c*Gk[4][4]+2.0*b*c*Gk[3][4]);
+	    
+	      pCov=new std::vector<double>;
+	      
+	      CV[0][0]=Gk[0][0];
+	      CV[0][1]=Gk[0][2];
+	      CV[0][2]=Gk[0][1];
+	      CV[0][3]=a*Gk[0][3];
+	      CV[0][4]=b*Gk[0][3]+c*Gk[0][4];
+	      CV[1][1]=Gk[2][2];
+	    
+	      CV[1][2]=Gk[1][2];
+	      CV[1][3]=a*Gk[2][3];
+	      CV[1][4]=b*Gk[2][3]+c*Gk[2][4];
+	      CV[2][2]=Gk[1][1];
+	      CV[2][3]=a*Gk[1][3];
+	      CV[2][4]=b*Gk[1][3]+c*Gk[1][4];
+	      CV[3][3]=a*a*Gk[3][3];
+	      CV[3][4]=a*(b*Gk[3][3]+c*Gk[3][4]);
+	      CV[4][4]=b*b*Gk[3][3]+2.0*b*c*Gk[3][4]+c*c*Gk[4][4];
+
+	      const Trk::FitQuality* pFQ=newtrack->fitQuality();  
+	      double chi2tot=pFQ->chiSquared();
+	      int ndoftot=pFQ->numberDoF();
+			    
+	      for(int i=0;i<5;i++)
+		for(int j=i;j<5;j++) pCov->push_back(CV[i][j]);
+	      pCov->push_back(ndoftot+0.001);
+
+	      const TrigInDetTrackFitPar* tidtfp = new TrigInDetTrackFitPar(D0,Phi0,Z0,Eta, Pt,
+									    errD0,errPhi0,errZ0,
+									    errEta,errPt,pCov);
+
+		  ATH_MSG_DEBUG("Total chi2 ="<<chi2tot<<" NDOF="<<ndoftot);
+		  ATH_MSG_DEBUG("Fitted parameters: d0="<<D0<<" phi0="<<Phi0<<" z0="<<Z0	
+			    <<" eta0="<<Eta<<" pt="<<Pt);
+	      if((ndoftot<0) || (fabs(Pt)<100.0) || (std::isnan(Pt)))
+		{
+	    ATH_MSG_DEBUG("Fit failed - possibly floating point problem");
+		  delete tidtfp;
+		  (*trIt)->chi2(1e8);
+		}
+	      else
+		{
+		  delete param;
+		  if(ndoftot>1) chi2tot/=ndoftot;
+		  (*trIt)->param(tidtfp);
+		  (*trIt)->chi2(chi2tot);
+		}
+	    }
+	}
+      else badFit=true;
+      if(badFit)
+	{
+		ATH_MSG_DEBUG("Offline fitter failed");
+	  (*trIt)->chi2(1e8);
+	}
+      delete newtrack;
+      if ( m_timers ) m_timer[2]->pause();
+    }
+  if(m_timers) 
+    {
+      m_timer[0]->stop();
+      m_timer[1]->stop();
+      m_timer[2]->stop();
+    }	  
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetPerigeeFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetPerigeeFitter.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..bae418867219609fca6bd0563832864a488ad710
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetPerigeeFitter.cxx
@@ -0,0 +1,258 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "StoreGate/StoreGateSvc.h" 
+#include "GaudiKernel/ToolFactory.h"
+#include "StoreGate/DataHandle.h"
+#include "GaudiKernel/MsgStream.h"
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetTrackFitter/TrigInDetPerigeeFitter.h"
+#include "MagFieldInterfaces/IMagFieldSvc.h"
+#include "TrigInDetTrackFitter/PerigeeFilteringNodes.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+TrigInDetPerigeeFitter::TrigInDetPerigeeFitter(const std::string& t, 
+					       const std::string& n,
+					       const IInterface*  p ): AthAlgTool(t,n,p),
+								       m_MagFieldSvc("AtlasFieldSvc",this->name())
+{
+  declareInterface< ITrigInDetTrackFitter >( this );
+  declareProperty( "StraightLineMode",     m_straightLineMode = false );
+  declareProperty( "AthenaFieldService", m_MagFieldSvc, "AtlasFieldSvc");
+  declareProperty( "doMultScattering", m_doMultScatt = true);
+  declareProperty( "doBremmCorrection", m_doBremmCorr=false);
+  
+  declareProperty( "Chi2Cut", m_DChi2 = 1000.0);
+}
+
+StatusCode TrigInDetPerigeeFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  StoreGateSvc* detStore;
+  sc = service("DetectorStore", detStore);
+  if ( sc.isFailure() ) { 
+    ATH_MSG_FATAL("DetStore service not found"); 
+    return StatusCode::FAILURE; 
+  };
+
+  if(!m_straightLineMode)
+    {
+	  sc = m_MagFieldSvc.retrieve();
+	  if(sc.isFailure()) 
+	    {
+	      ATH_MSG_ERROR("Unable to retrieve Athena MagFieldService");
+	      return StatusCode::FAILURE;
+	    }
+	  double pos[3];
+	  pos[0]=0.0;pos[1]=0.0;pos[2]=0.0;
+	  double field[3];
+	  m_MagFieldSvc->getField(pos,field);
+	  m_consb=0.029997*field[2];
+	  if(fabs(m_consb)<1e-6) 
+	    {
+	      m_straightLineMode=true;
+	      m_consb=0.6;
+	    }
+    }
+  else 
+    {
+      m_consb=0.6;
+    }
+  if(m_straightLineMode)
+    {
+      ATH_MSG_INFO("Straight line fitting mode ON ");
+    }
+  else
+    {
+      ATH_MSG_INFO("Field constant is set to "<<m_consb);
+    }
+  /*
+  ITrigTimerSvc* timerSvc;
+  sc = service( "TrigTimerSvc", timerSvc);
+  if( sc.isFailure() ) {
+    ATH_MSG_INFO<< "Unable to locate Service TrigTimerSvc " << endreq;
+    m_timers = false;
+  } 
+  else{
+    m_timers = true;  
+  }
+  if ( m_timers ) {
+    m_timer[0] = timerSvc->addItem("CreateNodes");
+    m_timer[1] = timerSvc->addItem("ForwardFilter");
+    m_timer[2] = timerSvc->addItem("Smoother");
+    m_timer[3] = timerSvc->addItem("TrigTrackPars");
+    m_timer[4] = timerSvc->addItem("CleanUp");
+    m_timer[5] = timerSvc->addItem("Validate");
+    m_timer[6] = timerSvc->addItem("Update");
+  }
+  */
+  ATH_MSG_INFO("TrigInDetPerigeeFitter constructed ");
+  return sc;
+}
+
+StatusCode TrigInDetPerigeeFitter::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+TrigInDetPerigeeFitter::~TrigInDetPerigeeFitter()
+{
+
+}
+
+
+void TrigInDetPerigeeFitter::fit(TrigInDetTrackCollection* recoTracks)
+{
+  int i,nType,nHits;
+  double chi2tot;
+  int ndoftot;
+  double Rk[5];
+  double Gk[15];
+  BarrelPerigeeFilteringNode* pBS;
+  DiscPerigeeFilteringNode* pDS;
+  std::vector<class BasePerigeeFilteringNode*> vpHits;
+
+  double Pt, Phi0, D0, Z0, Eta, errD0, errZ0, errEta, errPhi0, errPt;
+  double CV[5][5],a,b;
+  std::vector<double>* pCov;
+
+  vpHits.clear();
+  TrigInDetTrackCollection::iterator trIt = recoTracks->begin();
+  TrigInDetTrackCollection::iterator lastIt = recoTracks->end();
+  for(; trIt !=lastIt; trIt++) 
+    {
+      if((*trIt)->siSpacePoints()->size()==0) 
+	{
+		ATH_MSG_ERROR("Perigee Fit Failed -- TrigInDetTrack has no hits");
+	  continue;
+	}
+      std::vector<const TrigSiSpacePoint*>::iterator pSPIt=(*trIt)->siSpacePoints()->begin();
+      std::vector<const TrigSiSpacePoint*>::iterator lastSPIt=(*trIt)->siSpacePoints()->end();
+      for(; pSPIt != lastSPIt; pSPIt++) 
+	{
+	  const TrigSiSpacePoint* pSP=(*pSPIt);
+	  nType=(pSP->dr()>pSP->dz())?1:0;
+	  switch(nType)
+	    {
+	    case 0:
+	      {
+		pBS=new BarrelPerigeeFilteringNode(pSP);
+		vpHits.push_back(pBS);
+		break;
+	      }
+	    case 1: 
+	      {
+		pDS=new DiscPerigeeFilteringNode(pSP);
+		vpHits.push_back(pDS);
+		break;
+	      }
+	    }
+	}
+      nHits=vpHits.size();
+      TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>((*trIt)->param());
+      if(param==NULL)
+	{
+		ATH_MSG_ERROR("Perigee Fit Failed -- TrigInDetTrack has no parameters"); 
+	  for(std::vector<class BasePerigeeFilteringNode*>::iterator phIt=vpHits.begin();phIt!=vpHits.end();++phIt)
+	     {
+	       delete (*phIt);
+	     }
+	   vpHits.clear();
+	   continue;
+	}
+      else
+	{
+	  double tgHalfTheta=exp(-param->eta());
+	  Rk[4]=0.5*(1-tgHalfTheta*tgHalfTheta)/tgHalfTheta;
+	  if(fabs(Rk[4])<1e-6) Rk[4]=1e-6;
+	  Rk[2]=param->phi0();
+	  Rk[0]=0.5*m_consb/(param->pT()*1000.0);
+	  Rk[1]=param->a0();
+	  Rk[3]=param->z0();
+	  for(i=0;i<15;i++) Gk[i]=0.0;
+	  Gk[0]=0.01;Gk[2]=1.0;Gk[5]=10.0;Gk[9]=10.0;Gk[14]=0.2;
+	  if(m_straightLineMode)
+	    {
+	      Rk[0]=1e-10;Gk[0]=1e-8;
+	    }
+	  chi2tot=0.0;ndoftot=0;
+	  for(std::vector<class BasePerigeeFilteringNode*>::reverse_iterator pbhIt=vpHits.rbegin();
+	      pbhIt!=vpHits.rend();++pbhIt)
+	    {
+	      double dchi2=(*pbhIt)->m_getChi2(Rk,Gk);
+	      if(dchi2<m_DChi2)
+		{
+		  (*pbhIt)->m_acceptIt();
+		  chi2tot+=dchi2;
+		  ndoftot+=(*pbhIt)->m_getNdof();
+		  (*pbhIt)->m_runFilter(Rk,Gk);
+		}
+	      else (*pbhIt)->m_rejectIt();
+	      if(m_doMultScatt) (*pbhIt)->m_applyMultScatt(Rk,Gk);
+	      if(m_doBremmCorr) (*pbhIt)->m_applyEnergyLoss(Rk,Gk,-1); 
+	    }
+	  chi2tot/=ndoftot-5;
+	  Pt = -m_consb*0.5/Rk[0];   // put the right sign on Pt
+	  Phi0 = Rk[2];
+	  if(Phi0>M_PI) Phi0-=2*M_PI;
+	  if(Phi0<-M_PI) Phi0+=2*M_PI;
+	  Eta = log(Rk[4]+sqrt(1+Rk[4]*Rk[4]));
+	  Z0 = Rk[3];
+	  D0 = Rk[1];
+
+	  errD0 = sqrt(Gk[2]);
+	  errZ0 = sqrt(Gk[9]);
+	  errEta = sqrt(Gk[14]/(1+Rk[4]*Rk[4]));
+	  errPhi0 = sqrt(Gk[5]);
+	  errPt = 0.5*m_consb*sqrt(Gk[0])/(Rk[0]*Rk[0]);
+
+	  pCov=new std::vector<double>;
+	  a=1/sqrt(1+Rk[4]*Rk[4]);
+	  b=m_consb*0.5/(Rk[0]*Rk[0]);
+	  CV[0][0]=Gk[2];
+	  CV[0][1]=Gk[4];
+	  CV[0][2]=Gk[7];
+	  CV[0][3]=a*Gk[11];
+	  CV[0][4]=b*Gk[1];
+	  CV[1][1]=Gk[5];
+	  CV[1][2]=Gk[8];
+	  CV[1][3]=a*Gk[12];
+	  CV[1][4]=b*Gk[3];
+	  CV[2][2]=Gk[9];
+	  CV[2][3]=a*Gk[13];
+	  CV[2][4]=b*Gk[6];
+	  CV[3][3]=a*a*Gk[14];
+	  CV[3][4]=a*b*Gk[10];
+	  CV[4][4]=b*b*Gk[0];
+	  for(int i=0;i<5;i++)
+	    for(int j=i;j<5;j++) pCov->push_back(CV[i][j]);
+	  const TrigInDetTrackFitPar* tidtfp = new TrigInDetTrackFitPar(D0,Phi0,Z0,Eta, Pt,
+									errD0,errPhi0,errZ0,
+									errEta,errPt,pCov);
+		ATH_MSG_DEBUG("Perigee parameters: d0="<<D0<<" phi0="<<Phi0<<" z0="<<Z0
+			<<" eta0="<<Eta<<" pt="<<Pt);
+	  delete param;
+	  (*trIt)->param(tidtfp);
+	  (*trIt)->chi2(chi2tot);
+	  (*trIt)->siSpacePoints()->clear();
+	  int nRejected=0;
+	  for(std::vector<class BasePerigeeFilteringNode*>::iterator phIt=vpHits.begin();
+	      phIt!=vpHits.end();++phIt)
+	    {
+	      if((*phIt)->m_isAccepted())
+		{
+		  (*trIt)->siSpacePoints()->push_back((*phIt)->m_getTrigSp());
+		}
+	      else nRejected++;
+	      delete (*phIt);
+	    }
+		ATH_MSG_DEBUG(nHits<<" hits, "<<nRejected<<" rejected ");
+	  vpHits.clear();
+	}
+    }
+}
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetSctKFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetSctKFitter.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..68312bd8d6adb1c390c4b3d7f0251ee246d39904
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetSctKFitter.cxx
@@ -0,0 +1,2358 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigInDetSctKFitter
+// ( see header-file for details )
+// -------------------------------
+// ATLAS Collaboration
+////////////////////////////////////////////////////////////////////////////////
+
+#include "GaudiKernel/ToolFactory.h"
+#include "GaudiKernel/MsgStream.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetEvent/TrigInDetTrackCollection.h"
+#include "TrigInDetTrackFitter/TrigInDetSctKFitter.h"
+
+#include <cstring>
+using std::memset;
+
+TrigInDetSctKFitter::TrigInDetSctKFitter(const std::string& t, 
+					 const std::string& n,
+					 const IInterface*  p ): AthAlgTool(t,n,p)
+{
+  declareInterface< ITrigInDetTrackFitter >( this );
+  declareProperty( "doMultScattering", m_doMultScatt = true);
+  declareProperty( "doBremmCorrection", m_doBremmCorr=false);
+  declareProperty( "Chi2Cut", m_DChi2 = 200.0);
+  // set parameters
+  paramset = 0;
+  memset( minTrackRadius, 0, sizeof(minTrackRadius) );
+  memset( maxDChi2, 0, sizeof(maxDChi2) );
+  
+  maxDChi2[0] = m_DChi2;
+  maxDChi2[1] = m_DChi2;
+}
+
+StatusCode TrigInDetSctKFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  ATH_MSG_INFO("SctKFitter constructed ");
+  return sc;
+}
+
+StatusCode TrigInDetSctKFitter::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+TrigInDetSctKFitter::~TrigInDetSctKFitter()
+{
+
+}
+
+void TrigInDetSctKFitter::fit(TrigInDetTrackCollection* recoTracks)
+{
+
+  long ier, nHits, ihtype[73], ihdrop[73];
+  double wm1[15],cov1[15],par_kf[5],par_official[5],x0=0.,y0=0.,rp,cov2[15];
+  double rco[73],fco[73],zco[73],errr[73],errxy[73],errz[73],chi2;
+  bool electron=m_doBremmCorr;
+  
+  const double consb = 0.006;
+
+// to convert GeV to MeV and cm to mm
+  const double GeVToMeVConv = 1000.;
+  const double mmTocmConv = 0.1;
+  const double cmTommConv = 10.;
+
+  double Pt, Phi0, Eta, Z0, D0, errD0, errZ0, errEta, errPhi0, errPt;
+
+
+  TrigInDetTrackCollection::iterator trIt = recoTracks->begin();
+  TrigInDetTrackCollection::iterator lastIt = recoTracks->end();
+  for(; trIt !=lastIt; trIt++) 
+    {
+      if((*trIt)->siSpacePoints()->size()==0) 
+	{
+    ATH_MSG_ERROR("SctKFitter Failed -- TrigInDetTrack has no hits"); 
+	  continue;
+	}
+      std::vector<const TrigSiSpacePoint*>::iterator pSPIt=(*trIt)->siSpacePoints()->begin();
+      std::vector<const TrigSiSpacePoint*>::iterator lastSPIt=(*trIt)->siSpacePoints()->end();
+      int i=0;
+      for(; pSPIt != lastSPIt; pSPIt++) 
+	{
+	  const TrigSiSpacePoint* pSP=(*pSPIt);
+
+	  // to convert GeV to MeV and cm to mm
+	  rco[i] = pSP->r()*mmTocmConv;
+	  fco[i] = pSP->phi(); 
+	  zco[i] = pSP->z()*mmTocmConv;
+      
+	  errr[i] = pSP->dr()*mmTocmConv;
+	  errxy[i]= pSP->dphi() * pSP->r()*mmTocmConv; //this converts dPhi into dXY
+	  errz[i] = pSP->dz()*mmTocmConv;
+
+	  if( errr[i] > errz[i] ) 
+	    {
+	      ihtype[i]=1;                  //  endcap
+	    }
+	  else 
+	    {
+	      ihtype[i]=0;                  //  barrel
+	    }
+	  i++;
+	}
+      nHits=i;
+      tkffit(&nHits,&rco[0],&fco[0],&zco[0],&errxy[0],&errz[0],
+	     &errr[0],&ihtype[0],&rp,&par_kf[0],&wm1[0],&chi2,
+	     &ihdrop[0],&ier,electron);
+    
+      if ( ier ) {
+				ATH_MSG_ERROR("SctKFitter: error in tkffit -> " << ier); 
+				continue;
+      }
+      long dropped = 0;
+      for (long j=0; j<nHits; j++) {
+	dropped += ihdrop[j];
+      }
+        
+      //convert weight matrix to cov matrix
+      matrix_inverter(&wm1[0],&cov1[0],&ier);
+      if( ier ) {
+				ATH_MSG_ERROR(" SctKFitter: error in matrix conversion -> " << ier); 
+	continue;
+      }
+      cyl_prg_convertor(&par_kf[0], &cov1[0], &rp, &x0, &y0, 
+			&par_official[0], &cov2[0], &ier);
+    
+      // to convert GeV to MeV and cm to mm
+      Pt = -consb/par_official[4]*GeVToMeVConv;   // put the right sign on Pt
+      Phi0 = par_official[3];
+      Eta = -log(tan(par_official[2]/2.));
+      Z0 = par_official[1]*cmTommConv;
+      D0 = par_official[0]*cmTommConv;
+    
+      errD0 = sqrt(cov2[0])*cmTommConv;
+      errZ0 = sqrt(cov2[2])*cmTommConv;
+      errEta = sqrt(cov2[5])/fabs(sin(par_official[2]));
+      errPhi0 = sqrt(cov2[9]);
+      errPt = consb*sqrt(cov2[14])/(par_official[4]*par_official[4])*GeVToMeVConv;
+			ATH_MSG_DEBUG("Perigee parameters: d0="<<D0<<" phi0="<<Phi0<<" z0="<<Z0
+				<<" eta0="<<Eta<<" pt="<<Pt);
+
+      TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>((*trIt)->param());
+      const TrigInDetTrackFitPar* tidtfp = new TrigInDetTrackFitPar(D0,Phi0,Z0,Eta, Pt,
+								    errD0,errPhi0,errZ0,errEta,errPt,NULL);
+
+      if(param!=NULL) delete param;
+      (*trIt)->param(tidtfp);
+      (*trIt)->chi2(chi2);
+      (*trIt)->siSpacePoints()->clear();
+
+      std::vector<const TrigSiSpacePoint*> spacePointsOnTrack;
+     	
+      std::vector<const TrigSiSpacePoint*>::iterator  hitItr = (*trIt)->siSpacePoints()->begin();
+
+      for( long i = 0; i < nHits; ++i, ++hitItr )
+	if( ! ihdrop[i] )   
+	  (*trIt)->siSpacePoints()->push_back((*hitItr));
+    }
+}
+
+void TrigInDetSctKFitter::cyl_prg_convertor(double *pari, double *covi, double *r__, 
+				       double *xb, double *yb, 
+				       double *par, double *cov, long *ierr)
+{
+    double der11, der14, der15, der23, der45, cosf, sinf, curv;
+    long i__, j;
+    double rdphi, rsinb, cotth;
+    double x0, y0;
+    double tem, psi;
+
+/* Function   : Compute the "perigee" parameters (at the point of the closest*/
+/*          approach to the beam axis or to a reference position near a*/
+/*          secondary vertex) from the cylindrical-polar parameters */
+/*          of reconstructed tracks, and their covariance and weight */
+/*          matrices. */
+/*            For error propagation, an approximation is made, i.e. assuming*/
+/*          that the r coordinate of reference point is small w.r.t. the*/
+/*          radius of curvature. This is always true if the tracks are */
+/*          extrapolated to the positions where are close to the beam (or the*/
+/*          reference position near a secondary vertex) before calling this*/
+/*          routine. */
+/*            No account is taken for multiple scattering (m/s) in this*/
+/*          routine, so that, for the primary vertex, all tracks should be*/
+/*          extrapolated into the inside of the beam pipe before calling this*/
+/*          routine; i.e. the m/s should be taken care in the extrapolation.*/
+
+/* Arguments   : Input  : PARI(1:5)  :  track parameters in cylindrical-polar*/
+/*                                      coordinates, PARI(1) -- phi (rad.)*/
+/*                                                   PARI(2) -- z (cm)*/
+/*                                                   PARI(3) -- zeta (rad.)*/
+/*                                                   PARI(4) -- beta (rad.)*/
+/*                                                   PARI(5) -- 1/Rtr(1/cm)*/
+/*                        COVI(1:15) :  covariance matrix of PARI. */
+/*                                the numbering convention is  1 */
+/*                                                             2  3 */
+/*                                                             4  5  6 */
+/*                                                             7  8  9  10*/
+/*                                                             11 12 13 14 15*/
+/*                        R        :  the radius of the reference point where*/
+/*                                    above parameters are defined (in cm).*/
+/*                        XB,YB    :  coordinates of the "beam". */
+
+/*                Output : PAR(1:5)  :  "perigee" parameters, */
+/*                      1 : epsilon (impact par. in xy projection, with sign)*/
+/*                      2 : z coordinate */
+/*                      3 : theta */
+/*                      4 : phi angle */
+/*                      5 : 1/Rtr (Rtr = radius of curvature, with sign)*/
+/*                         COV(1:15) :  covariance matrix of PAR. */
+/*                         WGT(1:15) :  weight matrix of PAR. */
+
+/*  Errors      :  IERR = 0 :  no error; */
+/*                        1 :  incorrect data in inputs PARI, COVI or R; */
+/*                        2 :  error in converting COV (WGT not computed). */
+
+/*  Authers     :  P. BILLOIR,  S. QIAN  July 1990 */
+
+/*  Modified by :  S. QIAN for CMS       March 1994 */
+/*              (1) the output parameter "theta" is changed to "ctg(theta)";*/
+/*              (2) the appoximate perigee formula is replaced by a precise one.*/
+
+/**************************************************************************/
+
+/* Internal variables */
+
+/*      DATA CONSB /.0053964/ */
+
+/*If magnetic field is not 4 Tesla, this CONSB has to be modified, or to be*/
+/*   calculated by reading the field map. */
+
+    /* Parameter adjustments */
+    //    --wgt;
+    --cov;
+    --par;
+    --covi;
+    --pari;
+
+    /* Function Body */
+/* ________________________ */
+
+    *ierr = 0;
+    for (i__=1; i__<6; i__++) par[i__]=0.;
+
+/*   exit if incorrect data */
+
+    if (*r__ == 0. || pari[3] == 0. || covi[1] < 0. || 
+	covi[3] < 0. || covi[6] < 0. || covi[10] < 0. || covi[15] < 0.) {
+	*ierr = 1;
+	return;
+    }
+
+/*   computation of "perigee" parameters */
+
+    x0 = *r__ * cos(pari[1]) - *xb;
+    y0 = *r__ * sin(pari[1]) - *yb;
+    curv = pari[5];
+    psi = pari[1] + pari[4];
+    sinf = sin(psi);
+    cosf = cos(psi);
+    rsinb = x0 * sinf - y0 * cosf;
+
+/*   epsilon (impact parameter in xy projection, with geometrical sign) */
+/*   phi at perigee (range 0,2*PI) */
+
+    if (curv == 0.) {
+	par[1] = rsinb;
+	par[4] = psi;
+	rdphi = -x0 * cosf - y0 * sinf;
+    } else {
+	tem = (x0 * x0 + y0 * y0) * curv - rsinb * 2.;
+	par[1] =  - tem / (sqrt(curv * tem + 1.) + 1.);
+	par[4] = fmod(atan2(-x0*curv + sinf, y0*curv + cosf) + 2*M_PI, 2*M_PI);
+	rdphi = (fmod(par[4] - psi + 3*M_PI, 2*M_PI) - M_PI) / curv;
+    }
+
+/*   z of perigee */
+    cotth = 1. / tan(pari[3]);
+    par[2] = pari[2] + cotth * rdphi;
+
+/*   theta and 1/R at perigee (unchanged) */
+    par[3] = pari[3];
+    par[5] = curv;
+
+/*   Computation of covariance matrix */
+
+/*    transformation from (Phi, z, theta, beta, 1/Rtr) */
+/*                     to (Phi, z, theta, psi,  1/Rtr) */
+    cov[1] = covi[1];
+    cov[2] = covi[2];
+    cov[3] = covi[3];
+    cov[4] = covi[4];
+    cov[5] = covi[5];
+    cov[6] = covi[6];
+    cov[7] = covi[7]+covi[1];
+    cov[8] = covi[8]+covi[2];
+    cov[9] = covi[9]+covi[4];
+    cov[10] = covi[10]+covi[1]+2.*covi[7];
+    cov[11] = covi[11];
+    cov[12] = covi[12];
+    cov[13] = covi[13];
+    cov[14] = covi[14]+covi[11];
+    cov[15] = covi[15];
+
+/*   transformation from Phi to r*Phi */
+
+    for (i__ = 1; i__ <= 5; ++i__) {
+	j = i__ * (i__ - 1) / 2 + 1;
+	cov[j] *= *r__;
+    }
+    cov[1] *= *r__;
+    if (pari[5] == 0.) {
+	for(i__=11; i__<15; i__++) cov[i__]=0.;
+	cov[15] = 1.;
+	der15 = 0.;
+	der45 = 0.;
+    } else {
+
+/*   transformation from (r*Phi,   psi, z0,    theta, 1/Rtr) */
+/*                    to (epsilon, zp,  theta, phip,  1/Rtr) */
+
+/*  approximation for derivatives d(epsilon)/d(1/Rtr),    d(phip)/d(1/Rtr),*/
+/*           d(epsilon)/d(r*Phi),  d(epsilon)/d(psi), and  d(zp)/d(theta), */
+/*   the others are exactly or approximately 1 (diagonal terms) */
+/*                                        or 0 (non-diagonal terms). */
+	der15 = -(rdphi * rdphi) / 2.;
+	der45 = rdphi;
+    }
+
+    der11 = rdphi / sqrt(x0 * x0 + y0 * y0 + 1e-20);
+    der14 = -rdphi;
+    der23 = -(cotth * cotth + 1.) * rdphi;
+
+    cov[1] = der11 * der11 * cov[1] 
+           + der11 * 2. * (der14 * cov[7] + der15 * cov[11]) 
+           + der14 * (der14 * cov[10] + der15 * 2. * cov[14]) 
+           + der15 * der15 * cov[15];
+    cov[2] = der11 * (cov[2]  + der23 * cov[4]) 
+           + der14 * (cov[8]  + der23 * cov[9]) 
+           + der15 * (cov[12] + der23 * cov[13]);
+    cov[3] = cov[3] + der23 * 2. * cov[5] + der23 * der23 * cov[6];
+    cov[4] = der11 * cov[4] + der14 * cov[9] + der15 * cov[13];
+    cov[5] += der23 * cov[6];
+    cov[7] = der11 * (cov[7]  + der45 * cov[11]) 
+           + der14 * (cov[10] + der45 * cov[14]) 
+           + der15 * (cov[14] + der45 * cov[15]);
+    cov[8] =          cov[8]  + der23 * cov[9] 
+           + der45 * (cov[12] + der23 * cov[13]);
+    cov[9] += der45 * cov[13];
+    cov[10] = cov[10] + der45 * 2. * cov[14] + der45 * der45 * cov[15];
+    cov[11] =  der11 * cov[11] + der14 * cov[14] + der15 * cov[15];
+    cov[12] += der23 * cov[13];
+    cov[14] += der45 * cov[15];
+
+/*   transformation from theta to ctg(theta) 
+
+    tem = -1. - cotth * cotth;
+    cov[4]  *= tem;
+    cov[5]  *= tem;
+    cov[6]  *= tem*tem;
+    cov[9]  *= tem;
+    cov[13] *= tem;
+
+    invert matrix COV to get WGT 
+*/
+
+    //    tmxinv_(&cov[1], &wgt[1], ierr);
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::matrix_inverter(double *wgt, double *covm, long *ierr)
+{
+  double t11, s12, s13, s14, s15, t22, s23, s24, s25, t33, s34, s35,
+         t44, s45, t55, t45, t34, t35, t23, t24, t25, t12, t13, t14, t15;
+
+/************************************************************************/
+/*   Inversion of a (5x5) symmetric positive matrix (Cholesky method)   */
+/*   Internal variables are in double precision                         */
+/*   Check on positivity (IERR=2 if WGT not positive)                   */
+/*   COVM (output) may overwrite WGT (input)                            */
+/************************************************************************/
+
+    /* Parameter adjustments */
+    --covm;
+    --wgt;
+
+    /* Function Body */
+    *ierr = 0;
+
+    if (wgt[1] <= 0.) {
+        *ierr = 2;
+        return;
+    }
+    t11 = 1. / sqrt(wgt[1]);
+    s12 = wgt[2] * t11;
+    s13 = wgt[4] * t11;
+    s14 = wgt[7] * t11;
+    s15 = wgt[11] * t11;
+
+    t22 = wgt[3] - s12 * s12;
+    if (t22 <= 0.) {
+        *ierr = 2;
+        return;
+    }
+    t22 = 1. / sqrt(t22);
+    s23 = (wgt[5]  - s12 * s13) * t22;
+    s24 = (wgt[8]  - s12 * s14) * t22;
+    s25 = (wgt[12] - s12 * s15) * t22;
+
+    t33 = wgt[6] - s13 * s13 - s23 * s23;
+    if (t33 <= 0.) {
+        *ierr = 2;
+        return;
+    }
+    t33 = 1. / sqrt(t33);
+    s34 = (wgt[9]  - s13 * s14 - s23 * s24) * t33;
+    s35 = (wgt[13] - s13 * s15 - s23 * s25) * t33;
+
+    t44 = wgt[10] - s14 * s14 - s24 * s24 - s34 * s34;
+    if (t44 <= 0.) {
+        *ierr = 2;
+        return;
+    }
+    t44 = 1. / sqrt(t44);
+    s45 = (wgt[14] - s14 * s15 - s24 * s25 - s34 * s35) * t44;
+
+    t55 = wgt[15] - s15 * s15 - s25 * s25 - s35 * s35 - s45 * s45;
+    if (t55 <= 0.) {
+        *ierr = 2;
+        return;
+    }
+    t55 = 1. / sqrt(t55);
+
+    t45 = -t44 * (s45 * t55);
+    t34 = -t33 * (s34 * t44);
+    t35 = -t33 * (s34 * t45 + s35 * t55);
+    t23 = -t22 * (s23 * t33);
+    t24 = -t22 * (s23 * t34 + s24 * t44);
+    t25 = -t22 * (s23 * t35 + s24 * t45 + s25 * t55);
+    t12 = -t11 * (s12 * t22);
+    t13 = -t11 * (s12 * t23 + s13 * t33);
+    t14 = -t11 * (s12 * t24 + s13 * t34 + s14 * t44);
+    t15 = -t11 * (s12 * t25 + s13 * t35 + s14 * t45 + s15 * t55);
+
+    covm[1]  = t11 * t11 + t12 * t12 + t13 * t13 + t14 * t14 + t15 * t15;
+    covm[2]  = t12 * t22 + t13 * t23 + t14 * t24 + t15 * t25;
+    covm[3]  = t22 * t22 + t23 * t23 + t24 * t24 + t25 * t25;
+    covm[4]  = t13 * t33 + t14 * t34 + t15 * t35;
+    covm[5]  = t23 * t33 + t24 * t34 + t25 * t35;
+    covm[6]  = t33 * t33 + t34 * t34 + t35 * t35;
+    covm[7]  = t14 * t44 + t15 * t45;
+    covm[8]  = t24 * t44 + t25 * t45;
+    covm[9]  = t34 * t44 + t35 * t45;
+    covm[10] = t44 * t44 + t45 * t45;
+    covm[11] = t15 * t55;
+    covm[12] = t25 * t55;
+    covm[13] = t35 * t55;
+    covm[14] = t45 * t55;
+    covm[15] = t55 * t55;
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::tkffit(long *np, double *rcoord, double *phcoord, double *zcoord, 
+		double *errxy, double *errz, double *errr, long *ihtype, double *rf,
+		double *paraf, double *em1, double *chi2, long *ihdrop, long *ierr,
+		bool electron)
+{
+    /* System generated locals */
+    long i__1;
+    double r__1;
+
+    /* Local variables */
+    double pari[5], sinb, cons, sigr[3], sigz[3], sint, achi2;
+    long i__;
+    double d1, d2;
+    long i3[3];
+    double sigxy[3], r3, x0;
+    long ih;
+    double dp[5], parabb[6], parabe[6], w11, w22;
+    double wm[15], alrphi;
+    double wm1[15];
+    double fco[3], der[8], dir;
+    long ier;
+    double phi, rco[3], zco[3];
+    double c_b7=-9999., c_b8=9999., c_b9=.9999, c_b20=0.;
+    long c__0=0, c__1=1, c_n1=-1;
+
+    double fac1=M_PI/180.;
+
+/* -------------------------------- */
+
+/* Main routine of the Kalman-Filtering method for track fitting (at this */
+/*     moment for barrel tracker only; the forwards region and barrel/forward*/
+/*     mixed region will be integrated in later). Some subroutines are */
+/*     learnt from Prof. Billior. */
+
+/* In order to feed the vertex fitting package (i.e. TVSIMP and TVFULL), */
+/*     after calling this routine, another 2 routines have to be called */
+/*     sequentially: */
+/*     (1) TXTOBP: to extrapolate the fitted track into the beam-pipe and */
+/*                to take the multiple scattering of beam-pipe into account;*/
+/*         and/or, to re-order the track cylindrical-polar parameters from */
+/*                 (phi,z,theta,beta,1/R) to (phi,psi,z,theta,1/p), if the */
+/*                 track is generated outside the beam pipe (i.e. it does */
+/*                 not intercept with the beam pipe); */
+/*     (2) TCLPRG: to convert the cylindrical-polar parameters into the */
+/*         perigee parameters. */
+/*                                                   -Sijin QIAN,  3/4/1994*/
+
+/*These 2 steps have been already integrated into a vertex fitting steering*/
+/*    routine, i.e. TVSTEE; so now the fitted vertex and re-fitted tracks can*/
+/*     be obtained by calling TVSTEE right after this TKFFIT. */
+
+/*                                                   -Sijin QIAN, 22/4/1994*/
+
+/* The merge of the barrel and forward regions is completed. */
+/*                                                   -Sijin QIAN,  7/5/1994*/
+/* ------------------------------------------- */
+
+/*Modification for the OO tracker model: ignor the multiple scattering of the*/
+/*                                       material in the tracker temporarily.*/
+/*                                                   -Sijin QIAN, 29/6/1997*/
+/* ------------------------------------------- */
+
+/* Modification for the Atlas OO TRT tracker: */
+/*   (1) increase the max. points on track to 73; */
+/*   (2) activate the multiple scattering of material in the tracker, and the*/
+/*       material on each hit now depends on the number of hits. */
+/*                                                   -Sijin QIAN, 30/11/1998*/
+/* ------------------------------------------- */
+/* Input: np            -- Number of points on the track (max. 73, min. 3) */
+/*        rcoord(1:73)  -- r coordinates of points */
+/*                         (ordered from small to large) (cm) */
+/*        phcoord(1:73) -- phi coord. of points (radians) */
+/*        zcoord(1:73)  -- z coord. of points (cm) */
+/*        errxy(1:73)   -- error on r-phi (cm) */
+/*        errz(1:73)    -- error on z (cm) */
+/*        errr(1:73)    -- error on r (cm) */
+/*        ihtype(1:73)  -- type of the hit (0 for barrel, 1 for forward) */
+
+/*Output: rf           -- radial location of the fitted track parameters (cm)*/
+/*        paraf(1:5)   -- fitted track parameters (phi,z,theta,beta,1/R) */
+/*        em1(1:15)    -- error matrix for the parameters */
+/*                        (now it's a weight matrix for Atlas,   Dec.1,1998)*/
+/*        chi2         -- Chi2 of the fit */
+/*        ihdrop(1:73) -- index for the rejected hit (1 for yes, 0 for no)*/
+/*        ierr         -- error message, =1 np<=3 or np>73 */
+/*                                       =2 error in TFIT3P */
+/*                                       =3 error in TVTOXX or TXXTOV */
+/*                                       =4 error in TSOLVE */
+/* -------------------------------- */
+
+    /* Parameter adjustments */
+    --ihdrop;
+    --em1;
+    --paraf;
+    --ihtype;
+    --errr;
+    --errz;
+    --errxy;
+    --zcoord;
+    --phcoord;
+    --rcoord;
+
+    /* Function Body */
+    *ierr = 0;
+    if (*np < 3 || *np > 73) {
+	*ierr = 1;
+	return;
+    }
+    //cons = 83.3;
+    cons = 166.6;
+    for (i__ = 1; i__ <= 73; ++i__) ihdrop[i__] = 0;
+
+    x0 = .16 / double(*np);
+
+/* determine 3 initial points */
+
+    i3[0] = *np;
+    if(electron) {
+      i3[1] = *np - 1;
+      i3[2] = *np - 2;
+    } else {
+      i3[1] = (*np + 2) / 2;
+      i3[2] = 1;
+    }
+
+/* start the track from the outmost layer and extrapolate it from point */
+/*   to point. */
+
+    for (ih = 0; ih < 3; ++ih) {
+	rco[ih] = rcoord[i3[ih]];
+	fco[ih] = fmod(phcoord[i3[ih]] + 2*M_PI, 2*M_PI) / fac1;
+	zco[ih] = zcoord[i3[ih]];
+	sigxy[ih] = errxy[i3[ih]];
+	sigz[ih] = errz[i3[ih]];
+	sigr[ih] = errr[i3[ih]];
+    }
+
+    //    tfit3p_(rco, fco, zco, sigxy, sigz, sigr, &r3, pari, wm, chi2, &ier);
+
+    tfit3p(&rco[0], &fco[0], &zco[0], &sigxy[0], &sigz[0], &sigr[0], &r3, &pari[0], &wm[0], chi2, &ier);
+    if (ier != 0) {
+	*ierr = 2;
+	return;
+    }
+    pari[0] *= fac1;
+
+    dir = 1.;
+    //    tvtoxx_(pari, wm, &parabb[1], wm1);
+    tvtoxx(&pari[0], &wm[0], &parabb[1], &wm1[0]);
+    for(ih=0;ih<15;ih++) wm[ih]=wm1[ih];
+
+    parabb[0] = r3;
+    //    tswtch(&c__0, parabb, wm);
+    if (ihtype[*np] == 1) tswtch(&c__0, &parabb[0], &wm[0]);
+
+    for (ih = *np; ih >= 1; --ih) {
+	if (ihtype[ih] == 0) {
+	  /*   txtrpa_(parabb, &c__0, &rcoord[ih], &c_b7, &c_b8, &c_b9, &c__0, 
+		    parabe, der, &alrphi, &ier);
+	  */
+	    txtrpa(&parabb[0], &c__0, &rcoord[ih], &c_b7, &c_b8, &c_b9, &c__0, 
+		   &parabe[0], &der[0], &alrphi, &ier);
+	    if (ier != 0) {
+		goto L11;
+	    }
+	    txxdcy(&parabe[0], &parabb[0], &der[0]);
+	    txprcw(&wm[0], &der[0], &wm[0]);
+
+/* Add m/s into error matrix, then convert it to weight matrix. (Barrel) */
+
+	} else {
+	  /*
+	    txxpla_(parabb, &c__0, &zcoord[ih], &c_b20, &c_b8, &c__0, parabe, 
+		    der, &alrphi, &ier);
+	  */
+	    txxpla(&parabb[0], &c__0, &zcoord[ih], &c_b20, &c_b8, &c__0, &parabe[0], 
+		   &der[0], &alrphi, &ier);
+	    if (ier != 0) {
+		goto L11;
+	    }
+	    txxdpl(&parabe[0], &parabb[0], &der[0]);
+	    txprpw(&wm[0], &der[0], &wm[0]);
+
+/* Add m/s into error matrix, then convert it to weight matrix. (Forward) */
+
+	}
+	sint = sin(parabe[3]);
+	r__1 = parabe[5] * cons * sint;
+	//	tmscat_(&sint, &r__1, &x0, wm, &dir);
+	tmscat(&sint, &r__1, &x0, &wm[0], &dir);
+	if(electron==true) add_E_loss(&x0, &dir, &parabb[5], &wm[0]);
+
+	if (ih == i3[0] || ih == i3[1] || ih == i3[2]) {
+	    for(long ii=0; ii<6; ii++) parabb[ii]=parabe[ii];
+	    goto L11;
+	}
+
+	parabb[0] = parabe[0];
+	if (ihtype[ih] == 0) {
+/* Computing 2nd power */
+	    r__1 = rcoord[ih] / errxy[ih];
+	    w11 = r__1 * r__1;
+	    d1 = fmod(phcoord[ih] - parabe[1] + 2*M_PI + M_PI, 2*M_PI) - M_PI;
+	    w22 = 1. / (errz[ih] * errz[ih]);
+	    d2 = zcoord[ih] - parabe[2];
+	} else {
+	    r3 = sqrt(parabe[1] * parabe[1] + parabe[2] * parabe[2]);
+	    phi = fmod(atan2(parabe[2], parabe[1])+2*M_PI,2*M_PI);
+	    //	    trf2xy_(&c_n1, &r3, &phi, wm);
+	    trf2xy(&c_n1, &r3, &phi, &wm[0]);
+	    w11 = 1. / (errr[ih] * errr[ih]);
+	    d1 = rcoord[ih] - r3;
+/* Computing 2nd power */
+	    r__1 = rcoord[ih] / errxy[ih];
+	    w22 = r__1 * r__1;
+	    d2 = fmod(phcoord[ih] - phi + 2*M_PI + M_PI, 2*M_PI) - M_PI;
+	}
+
+/* Add a point to the track, update the parameter and weight matrix. */
+
+	taddpt(&d1, &d2, &w11, &w22, &dp[0], &wm[0], &achi2, &ier);
+
+	if (ier != 0) {
+	    ihdrop[ih] = 1;
+	    for(long ii=1; ii<6; ii++) parabb[ii]=parabe[ii];
+	} else {
+	    if (ihtype[ih] == 0) {
+	        for(long ii=1; ii<6; ii++) parabb[ii]=parabe[ii]+dp[ii-1];
+		sinb = fabs(sin(parabb[4]));
+	    } else {
+		r3 += dp[0];
+		phi += dp[1];
+		parabb[1] = r3 * cos(phi);
+		parabb[2] = r3 * sin(phi);
+	        for(long ii=3; ii<6; ii++) parabb[ii]=parabe[ii]+dp[ii-1];
+		sinb = fabs(sin(parabb[4] - phi));
+		trf2xy(&c__1, &r3, &phi, &wm[0]);
+	    }
+
+	    if (sinb >= 1.) {
+		*ierr = 2;
+		return;
+	    }
+	    *chi2 += achi2;
+/* 		parabb(6)=1./(1./parabb(6)-SIGN(8.e-2,PARABb(6))) */
+	}
+L11:
+	if (ih==1) goto L10;
+
+	if ((i__1 = ihtype[ih] - ihtype[ih - 1]) < 0) {
+	    goto L311;
+	} else if (i__1 == 0) {
+	    goto L312;
+	} else {
+	    goto L313;
+	}
+L311:
+	tswtch(&c__0, &parabb[0], &wm[0]);
+L312:
+	goto L10;
+L313:
+	tswtch(&c__1, &parabb[0], &wm[0]);
+L10:
+	;
+    }
+
+    if (ihtype[1] == 1) {
+	tswtch(&c__1, &parabb[0], &wm[0]);
+    }
+    for(long ii=1; ii<6; ii++) paraf[ii]=parabb[ii];
+    *rf = parabb[0];
+    for(long ij=1; ij<16; ij++) em1[ij]=wm[ij-1];
+/*        CALL TMXINV(WM,EM1,IERR) */
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::tfit3p(double *rco, double *fco, double *zco, double *sigxy, 
+		   double *sigz, double *sigr, double *r3, double *para,
+		   double *wgc, double *chi2c, long *ierr)
+{
+    double der13, der23, der24, der15, der25, cosa, d21sq, fmax, d23sq; 
+    double sina, sinb, sdet, tanl, tnsb, rotf, rinv, rtrk, alph3; 
+    double alph[2], sinb2, r1, r2, r__3, sinb22[2];
+
+    long i;
+    double x[3], y[3], z[3];
+    
+    double z0, sumwz, d23, ds[2], xc, yc, rr[3], sumwsz, fac;
+    double dx21, dy21, dx23, dy23;
+    double wff[3], tem, rfz[9]	/* was [3][3] */, wzz[3];
+    double d_r = M_PI/180.;
+
+/* ---------------------------------------------------------- */
+
+/* Subroutine for fitting 3 points to a helix */
+/* 
+   error code: ierr=1 --- Track radius too small ( < 0.5 GeV, i.e. 83 cm)
+                   =2 --- sin(beta) >=1
+                   =3 --- two hits have the same (x,y)
+*/
+
+/* ---------------------------------------------------------- */
+
+    /* Parameter adjustments */
+    --wgc;
+    --para;
+    --sigr;
+    --sigz;
+    --sigxy;
+    --zco;
+    --fco;
+    --rco;
+
+    /* Function Body */
+    for (i = 1; i <= 3; ++i) {
+	rfz[i * 3 - 3] = rco[i];
+	rfz[i * 3 - 2] = fco[i];
+	rfz[i * 3 - 1] = zco[i];
+    }
+
+/* Rotate 3 points to 0-90 degrees region */
+
+    fmax = std::max(std::max(rfz[1], rfz[4]),rfz[7]);
+    if (fmax <= 90.) {
+	rotf = 0.;
+	goto L77;
+    }
+
+    if (fmax >= 270. && std::min(std::min(rfz[1],rfz[4]),rfz[7]) <= 90.) {
+	rotf = 10. - fmax;
+	goto L77;
+    }
+    rotf = 80. - fmax;
+L77:
+
+/* The X and Y coords. of 3 points */
+
+    for (i = 1; i <= 3; ++i) {
+	x[i - 1] = rfz[i * 3 - 3] * cos((rfz[i * 3 - 2] + rotf) * d_r);
+	y[i - 1] = rfz[i * 3 - 3] * sin((rfz[i * 3 - 2] + rotf) * d_r);
+	z[i - 1] = rfz[i * 3 - 1];
+	rr[i - 1] = rfz[i * 3 - 3];
+    }
+
+/* To calculate the parameters (in XY projection) at the point 3 */
+
+   dy21 = y[1] - y[0];
+    dx21 = x[1] - x[0];
+    d21sq = dx21 * dx21 + dy21 * dy21;
+    dy23 = y[1] - y[2];
+    dx23 = x[1] - x[2];
+    d23sq = dx23 * dx23 + dy23 * dy23;
+    if (d21sq==0 || d23sq==0) {*ierr=3; return;}
+    d23 = sqrt(d23sq);
+
+    tem = dx21 * dy23 - dx23 * dy21;
+    if (tem == 0.) {
+	rtrk = 15000.;
+	xc=yc=sdet=0.;
+    } else {
+      sdet = .5 / tem;
+      xc = x[1] + sdet * (d23sq * dy21 - d21sq * dy23);
+      yc = y[1] + sdet * (d21sq * dx23 - d23sq * dx21);
+      
+      r1 = xc - x[1];
+      r2 = yc - y[1];
+      rtrk = sqrt(r1 * r1 + r2 * r2);
+    }
+
+/* If the radius of helix .LT. 10 m: exact solution */
+
+    //    if(rtrk<1000.) {
+
+/* To reject the helix with radius .LT. the RMIN */
+
+/* For Pmin=1GeV */
+/*        IF(RTRK.LT.72.) THEN */
+/* For Pmin=0.5GeV */
+    //      if (rtrk < 17.) {
+    if (rtrk < minTrackRadius[paramset]) {
+	*ierr = 1;
+	return;
+      }
+
+/* About the sign of the curvature */
+
+      if (sdet < 0.) rtrk *= -1.;
+      rinv = 1. / rtrk;
+
+/* Angles at the point 3 and curvature distances of 3-2 and 3-1 */
+
+    if(tem!=0) {
+
+      sina = (x[2] - xc) * rinv;
+      cosa = (yc - y[2]) * rinv;
+      alph3 = atan2(sina, cosa);
+      alph[1] = atan2((x[1] - xc) * rinv, (yc - y[1]) * rinv);
+      alph[0] = atan2((x[0] - xc) * rinv, (yc - y[0]) * rinv);
+      ds[1] = rtrk * (alph[1] - alph3);
+      ds[0] = rtrk * (alph[0] - alph3);
+      for(i=0; i<2; i++) {
+	sinb = (sin(alph[i]) * x[i] - cos(alph[i]) * y[i]) / rr[i];
+	if (fabs(sinb) >= 1.) {
+	  *ierr = 2;
+	  return;
+	}
+	sinb22[i]=sinb*sinb;
+      }
+    }
+
+/* If the radius of helix .GT. 10 m: approximation to the 1st order of 1/r */
+
+    else {
+      
+      double rrr = 2.*(y[1]-(y[2]*dx21-y[0]*dx23)/(dx21-dx23))/(dx23*dx21);
+      double tem1=dx23/d23;
+      tem1 = tem1*tem1*tem1*rrr;
+      sina = dy23/d23 - fabs(.5*d23*tem1)*(dy23>0. ? 1. : -1.);
+      if(fabs(sina)>=1.) {
+	*ierr = 1;
+	return;
+      }
+      cosa = sqrt(1.-sina*sina)*(dx23>0. ? 1. : -1.);
+      ds[1] = d23;
+      ds[0] = sqrt(d21sq)+d23;
+    }
+
+/* Parameters phi and sin(beta) at point 3 */
+
+    sinb = (sina * x[2] - cosa * y[2]) / rr[2];
+    if (fabs(sinb) >= 1.) {
+	*ierr = 2;
+	return;
+    }
+   
+    *r3 = rr[2];
+    para[1] = rfz[7];
+    para[3] = sinb;
+    para[5] = rinv;
+
+/* Calculation of weight on phi, z, sin(beta), cot(theta) and 1/R */
+/*   and adjustment on z, cot(theta) */
+
+    tanl = (z[1] - z[2]) / d23;
+    tnsb = sinb * tanl;
+
+    for(i=1;i<16;i++) wgc[i]=0.;
+
+/* Contribution of the point 3 */
+
+    sinb2 = sinb * sinb;
+    wgc[1] = *r3 * *r3 / (sigxy[3] * sigxy[3] + 
+			  sigr[3] * sigr[3] * sinb2 / (1. - sinb2));
+    r2 = sigr[3] * tanl;
+    wgc[3] = 1. / (sigz[3] * sigz[3] + r2 * r2 / (1. - sinb2));
+    wzz[2] =wgc[3];
+
+    if(tem==0) sinb22[0]=sinb22[1]=sinb2;
+
+    sumwz = wgc[3] * z[2];
+    sumwsz = 0.;
+
+/* Contribution of points 1 and 2 */
+
+    for (i = 1; i < 3; ++i) {
+
+/* Contribution at weight on phi and sin(beta) */
+
+	r1 = rr[i - 1];
+	wff[i- 1] = r1 * r1 / (sigxy[i] * sigxy[i] + 
+			 sigr[i] * sigr[i] * sinb22[i-1] / (1. - sinb22[i-1]));
+	r2 = sigr[i] * tanl;
+	wzz[i- 1] = 1. / (sigz[i] * sigz[i] + r2 * r2 / (1. - sinb22[i-1]));
+
+	fac = ds[i - 1] / (1. - sinb22[i-1]);
+	der24 = ds[i - 1];
+	der23 = fac * tnsb;
+	der13 = fac / rr[i - 1];
+	der15 = (rr[i - 1] - rr[2]) * .5 * der13;
+	der25 = der15 * tnsb;
+	wgc[1] += wff[i - 1];
+	wgc[4] += wff[i - 1] * der13;
+	wgc[6] += wff[i - 1] * der13 * der13;
+	wgc[11] += wff[i - 1] * der15;
+	wgc[13] += wff[i - 1] * der15 * der13;
+	wgc[15] += wff[i - 1] * der15 * der15;
+	
+/* Contribution at weight on z and cot(theta) */
+
+	wgc[3] += wzz[i - 1];
+	wgc[8] += wzz[i - 1] * der24;
+	wgc[10] += wzz[i - 1] * der24 * der24;
+	
+	sumwz += z[i - 1] * wzz[i - 1];
+	sumwsz += z[i - 1] * wzz[i - 1] * der24;
+
+/*Contribution of correlations between (phi,sin(beta),1/R) and (z,cot(
+theta))*/
+	wgc[5] += wzz[i - 1] * der23;
+	wgc[6] += wzz[i - 1] * der23 * der23;
+	wgc[9] += wzz[i - 1] * der23 * der24;
+	wgc[12] += wzz[i - 1] * der25;
+	wgc[13] += wzz[i - 1] * der25 * der23;
+	wgc[14] += wzz[i - 1] * der25 * der24;
+	wgc[15] += wzz[i - 1] * der25 * der25;
+    }
+
+/* Resolution of the system equation on z,cot(theta) */
+
+    sdet = wgc[3] * wgc[10] - wgc[8] * wgc[8];
+    if (sdet == 0.) {
+/*       print *,' Tfit3p : sdet = 0. ' */
+	sdet = 0.;
+    } else {
+	sdet = 1. / sdet;
+    }
+/* wiw*      SDET=1./(WGC(3)*WGC(10)-WGC(8)**2) */
+    z0 = (wgc[10] * sumwz - wgc[8] * sumwsz) * sdet;
+    tanl = (wgc[3] * sumwsz - wgc[8] * sumwz) * sdet;
+
+/* Calculation of chi2 */
+
+    r1 = z[2] - z0;
+    r2 = z[1] - z0 - tanl * ds[1];
+    r__3 = z[0] - z0 - tanl * ds[0];
+    *chi2c = wzz[2] * (r1 * r1) + wzz[1] * (r2 * r2) + wzz[0] * (r__3 * r__3);
+
+    para[2] = z0;
+    para[4] = tanl;
+
+/* 	print *,'chi2 in fit3=',chi2c */
+    *ierr = 0;
+
+    return;
+
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::tvtoxx(double *pari, double *wctr, double *par, double *wf)
+{
+    double r1,cf;
+
+/* ----------------------------------------------- */
+/* The routine for transformation from internal parameters to */
+/*   cylindrical-polar parameters. */
+/*                                            -By Sijin QIAN, 3/1994 */
+
+/* Input: pari --- internal track parameters (phi,Z,sinb,ctg(theta),1/Rtr)
+ */
+/*        WCTR --- weight matrix of pari, packed in lower triangle. */
+
+/* Output: PAR(5) --- Cylindrical-polar track parameters */
+/*                      (Phi,Z,Theta,beta,1/Rtr) */
+/*         wf(15) --- Weight matrix corresponding to PAR, */
+/*                      packed in lower triangle. */
+/* ----------------------------------------------- */
+
+/* Transformation for WEIGHT Matrix from (sin(beta),ctg(theta)) */
+/*                                    to (theta,    sin(beta)) */
+
+    /* Parameter adjustments */
+    --wf;
+    --par;
+    --wctr;
+    --pari;
+   
+    //    for(int i=0; i<5; i++) { par[i]=pari[i]; }
+    //    for(int i=0; i<15; i++){ wf[i]=wctr[i]; }
+    par[2]=pari[2];
+    par[5]=pari[5];
+    for(long i=1; i<4; i++){ wf[i]=wctr[i]; }
+    wf[11]=wctr[11];
+    wf[12]=wctr[12];
+    wf[15]=wctr[15];
+
+    wf[ 4] = wctr[ 7];
+    wf[ 7] = wctr[ 4];
+    wf[ 5] = wctr[ 8];
+    wf[ 8] = wctr[ 5];
+    wf[ 6] = wctr[10];
+    wf[10] = wctr[ 6];
+    wf[13] = wctr[14];
+    wf[14] = wctr[13];
+
+    // had to modify the following to compile on HP-Unix
+    if (pari[4]==0.) {
+      par[3] = 0.5*M_PI;
+    } else {
+      double at = atan(1./pari[4]);
+      par[3] = fmod(at+M_PI, M_PI); 
+    }
+    //par[3] = pari[4]==0. ? 0.5*pi : fmod(at+pi, pi); 
+
+    r1 = sin(par[3]);
+    cf = -1. / (r1 * r1);
+
+    //    vscale(&wf[4], &cf, &wf[4], &c3);
+    wf[4]  = cf * wf[4];
+    wf[5]  = cf * wf[5];
+    wf[6]  = cf * wf[6] * cf;
+    wf[9]  = cf * wctr[9];
+    wf[13] = cf * wf[13];
+
+/* Transformation from sin(beta) to beta */
+
+    par[1] = fmod(pari[1]+2*M_PI, 2*M_PI);
+    par[4] = asin(pari[3]);
+    cf = cos(par[4]);
+    //    vscale(&wf[7], &cf, &wf[7], &c4);
+    wf[ 7] = cf * wf[ 7];
+    wf[ 8] = cf * wf[ 8];
+    wf[ 9] = cf * wf[ 9];
+    wf[10] = cf * wf[10] * cf;
+    wf[14] = cf * wf[14];
+
+    return ;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::txprcw(double *wgi, double *der, double *wgf)
+{
+  double w31, w41, w51, w52, w53, w54, w55, w44, w43, w42, w33, w32;
+/*                                                                      * 
+*/
+/*   propagation of weight matrix from a cylinder to another one        * 
+*/
+/*   Input  : WGI  : initial weight matrix                              * 
+*/
+/*            DER  : inverse derivatives                                * 
+*/
+/*   Output : WGF  : final weight matrix (may overwrite WGI)            * 
+*/
+/* ***********************************************************************
+*/
+/*   computation of   A  =  DER transp * WG */
+
+    /* Parameter adjustments */
+    --wgf;
+    --der;
+    --wgi;
+
+    /* Function Body */
+    w55 = wgi[11] * der[3] + wgi[12] * der[6] + wgi[14] * der[8] + wgi[15];
+    w54 = wgi[7] * der[3] + wgi[8] * der[6] + wgi[10] * der[8] + wgi[14];
+    w53 = wgi[4] * der[3] + wgi[5] * der[6] + wgi[9] * der[8] + wgi[13];
+    w52 = wgi[2] * der[3] + wgi[3] * der[6] + wgi[8] * der[8] + wgi[12];
+    w51 = wgi[1] * der[3] + wgi[2] * der[6] + wgi[7] * der[8] + wgi[11];
+
+    w44 = wgi[7] * der[2] + wgi[8] * der[5] + wgi[10] * der[7];
+    w43 = wgi[4] * der[2] + wgi[5] * der[5] + wgi[9] * der[7];
+    w42 = wgi[2] * der[2] + wgi[3] * der[5] + wgi[8] * der[7];
+    w41 = wgi[1] * der[2] + wgi[2] * der[5] + wgi[7] * der[7];
+
+    w33 = wgi[4] * der[1] + wgi[5] * der[4] + wgi[6];
+    w32 = wgi[2] * der[1] + wgi[3] * der[4] + wgi[5];
+    w31 = wgi[1] * der[1] + wgi[2] * der[4] + wgi[4];
+
+/*   computation of   A * DER */
+
+    wgf[1] = wgi[1];
+    wgf[2] = wgi[2];
+    wgf[3] = wgi[3];
+
+    wgf[4] = w31;
+    wgf[5] = w32;
+    wgf[6] = w31 * der[1] + w32 * der[4] + w33;
+
+    wgf[7] = w41;
+    wgf[8] = w42;
+    wgf[9] = w41 * der[1] + w42 * der[4] + w43;
+    wgf[10] = w41 * der[2] + w42 * der[5] + w44 * der[7];
+
+    wgf[11] = w51;
+    wgf[12] = w52;
+    wgf[13] = w51 * der[1] + w52 * der[4] + w53;
+    wgf[14] = w51 * der[2] + w52 * der[5] + w54 * der[7];
+    wgf[15] = w51 * der[3] + w52 * der[6] + w54 * der[8] + w55;
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::txprpw(double *wgi, double *der, double *wgf)
+{
+  double w31, w41, w51, w52, w53, w54, w55, w44, w43, w42, w34, w33, w32;
+
+/*   propagation of weight matrix from a plane to another one           * 
+*/
+/*   Input  : WGI  : initial weight matrix                              * 
+*/
+/*            DER  : inverse derivatives                                * 
+*/
+/*   Output : WGF  : final weight matrix (may overwrite WGI)            * 
+*/
+/* ***********************************************************************
+ */
+/*   propagation of weight matrix from a plane to a plane */
+
+/*   computation of   W  =  DER transp * WG */
+
+    /* Parameter adjustments */
+    --wgf;
+    --der;
+    --wgi;
+
+    /* Function Body */
+    w55 = wgi[11] * der[3] + wgi[12] * der[6] + wgi[14] * der[8] + wgi[15];
+    w54 = wgi[7] * der[3] + wgi[8] * der[6] + wgi[10] * der[8] + wgi[14];
+    w53 = wgi[4] * der[3] + wgi[5] * der[6] + wgi[9] * der[8] + wgi[13];
+    w52 = wgi[2] * der[3] + wgi[3] * der[6] + wgi[8] * der[8] + wgi[12];
+    w51 = wgi[1] * der[3] + wgi[2] * der[6] + wgi[7] * der[8] + wgi[11];
+
+    w44 = wgi[7] * der[2] + wgi[8] * der[5] + wgi[10];
+    w43 = wgi[4] * der[2] + wgi[5] * der[5] + wgi[9];
+    w42 = wgi[2] * der[2] + wgi[3] * der[5] + wgi[8];
+    w41 = wgi[1] * der[2] + wgi[2] * der[5] + wgi[7];
+
+    w34 = wgi[7] * der[1] + wgi[8] * der[4] + wgi[9] + wgi[10] * der[7];
+    w33 = wgi[4] * der[1] + wgi[5] * der[4] + wgi[6] + wgi[9] * der[7];
+    w32 = wgi[2] * der[1] + wgi[3] * der[4] + wgi[5] + wgi[8] * der[7];
+    w31 = wgi[1] * der[1] + wgi[2] * der[4] + wgi[4] + wgi[7] * der[7];
+
+/*   computation of   W * DER */
+
+    wgf[1] = wgi[1];
+    wgf[2] = wgi[2];
+    wgf[3] = wgi[3];
+
+    wgf[4] = w31;
+    wgf[5] = w32;
+    wgf[6] = w31 * der[1] + w32 * der[4] + w33 + w34 * der[7];
+
+    wgf[7] = w41;
+    wgf[8] = w42;
+    wgf[9] = w41 * der[1] + w42 * der[4] + w43 + w44 * der[7];
+    wgf[10] = w41 * der[2] + w42 * der[5] + w44;
+
+    wgf[11] = w51;
+    wgf[12] = w52;
+    wgf[13] = w51 * der[1] + w52 * der[4] + w53 + w54 * der[7];
+    wgf[14] = w51 * der[2] + w52 * der[5] + w54;
+    wgf[15] = w51 * der[3] + w52 * der[6] + w54 * der[8] + w55;
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+
+/* *********************************************************************** */
+/*                                                                      * */
+/*   compute derivatives for a propagation cylinder -> cylinder         * 
+*/
+/*   knowing the initial and final parameters                           * 
+*/
+/*   see routine TXTRPA for the definition of PARAMI,PARAMF,DER         * 
+*/
+/*   and comments                                                       * 
+*/
+/* ***********************************************************************
+ */
+
+void TrigInDetSctKFitter::txxdcy(double *parami, double *paramf, double *der)
+{
+/* Local variables */
+     double radf, fact, radi, dphi, cosb, sinb, rtrk, cdphi, cosbf, 
+	    ccpsf, sinbf, ccpsi, cpsif, rdphi, cpsii, sdphi, cotth, 
+	    scpsi, spsif, spsii, xc, yc, rc2;
+     
+     double dphimn=0.01;
+
+/*   radius of the helix, cot(theta) and sin(beta),cos(beta) at both ends 
+*/
+    /* Parameter adjustments */
+    --der;
+    --paramf;
+    --parami;
+
+    /* Function Body */
+    radi = parami[1];
+    radf = paramf[1];
+    rtrk = 1. / parami[6];
+    cotth = 1. / tan(parami[4]);
+    sinb = sin(parami[5]);
+    cosb = cos(parami[5]);
+    sinbf = sin(paramf[5]);
+    cosbf = cos(paramf[5]);
+
+/*   variation DPHI of phi angle */
+
+    dphi = paramf[2] + paramf[5] - parami[2] - parami[5];
+    dphi = fmod(dphi + 2. * 2*M_PI + M_PI, 2*M_PI) - M_PI;
+
+/*   if |DPHI| >  DPHIMN , use "exact" formulae */
+
+    if (fabs(dphi) >= dphimn) {
+	xc = radi - rtrk * sinb;
+	yc = rtrk * cosb;
+
+	rc2 = xc * xc + yc * yc;
+
+	ccpsi = radi - rtrk * sinb;
+	scpsi = rtrk * cosb;
+	ccpsf = radf - rtrk * sinbf;
+	//	scpsf = rtrk * cosbf;
+
+	cpsii = rtrk - radi * sinb;
+	spsii = -radi * cosb;
+	cpsif = rtrk - radf * sinbf;
+	spsif = -radf * cosbf;
+
+	sdphi = sin(dphi);
+	cdphi = cos(dphi);
+
+	der[1] = 0.;
+	fact   = -rtrk / spsif;
+	der[2] = sdphi * fact;
+	der[3] = fact * rtrk * (1. - cdphi);
+	der[4] = -rtrk * dphi * (1. + cotth * cotth);
+	der[5] = rtrk * cotth * (radf * ccpsf * spsii / spsif - radi * ccpsi) 
+		/ rc2;
+	der[6] = rtrk * rtrk * cotth * (-dphi + sinbf / cosbf - (radi * scpsi 
+		+ radf * ccpsf * cpsii / spsif) / rc2);
+	der[7] = spsii / spsif;
+	der[8] = rtrk * (cpsif - cpsii) / spsif;
+    }
+
+/*   if |DPHI| < DPHIMN , use first order in 1/R */
+    else {
+	rdphi  = rtrk * dphi;
+	der[1] = 0.;
+	der[2] = rdphi / (radf * cosbf);
+	der[3] = rdphi * .5 * der[2];
+	der[4] = -rdphi * (cotth * cotth + 1.);
+	der[5] = radi * cotth * sin(paramf[2] - parami[2]) / cosbf;
+	der[6] = rdphi * .5 * der[5];
+	der[7] = radi * cosb / (radf * cosbf);
+	der[8] = rdphi * .5 * (der[7] + 1.);
+    }
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+/* ******************************************************************** * 
+*/
+/*   compute derivatives for a propagation plane -> plane               * 
+*/
+/*   knowing the initial and final parameters                           * 
+*/
+/*   see routine TXXPLA for the definition of PARAMI,PARAMF,DER         * 
+*/
+/*   and comments                                                       * 
+*/
+/* ***********************************************************************
+ */
+
+void TrigInDetSctKFitter::txxdpl(double *parami, double *paramf, double *der)
+{
+
+ /* Local variables */
+    double dphi, rtrk, cosf0, cosf1, sinf0, sinf1, dcosf, dsinf, 
+           rdphi, tanth, dz;
+
+ /* Parameter adjustments */
+    --der;
+    --paramf;
+    --parami;
+
+    /* Function Body */
+    cosf0 = cos(parami[5]);
+    cosf1 = cos(paramf[5]);
+    sinf0 = sin(parami[5]);
+    sinf1 = sin(paramf[5]);
+    tanth = tan(parami[4]);
+    dz = paramf[1] - parami[1];
+    rdphi = tanth * dz;
+
+    double tem = (tanth * tanth + 1.) * dz;
+    der[1] = tem * cosf1;
+    der[4] = tem * sinf1;
+    der[7] = tem * parami[6];
+    der[8] = rdphi;
+
+    dphi = rdphi * parami[6];
+
+/*   "exact" formulae if |DPHI| > DPHIMN */
+
+    if (fabs(dphi) >= .01) {
+	rtrk = 1. / parami[6];
+	dcosf = cosf1 - cosf0;
+	dsinf = sinf1 - sinf0;
+	der[2] = rtrk * dcosf;
+	tem = rtrk *rtrk;
+	der[3] = tem * (dphi * cosf1 - dsinf);
+	der[5] = rtrk * dsinf;
+	der[6] = tem * (dphi * sinf1 + dcosf);
+
+/*   first order in 1/R if |DPHI| < DPHIMN */
+    } else {
+	der[2] = -rdphi * sinf0;
+	der[3] = rdphi * .5 * der[2];
+	der[5] = rdphi * cosf0;
+	der[6] = rdphi * .5 * der[5];
+    }
+
+    return ;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+/* ********************************************************************** 
+*/
+/*   change from "plane" parameters to "barrel" parameters              * 
+*/
+/*   at a given point (without propagation), or conversely,             * 
+*/
+/*   and tranform the deviations from ref. traj. and the weight matrix  * 
+*/
+/*   Input   :   ITYP      :  type to be changed ('PLAN'=1 or 'CYLI'=0) * 
+*/
+/*               PAR(1-6)  :  plane  parameters                         * 
+*/
+/*                             z(fixed),x,y,theta,phi,1/R               * 
+*/
+/*                            or cylinder parameters                    * 
+*/
+/*                             r(fixed),Phi,z,theta,beta=phi-Phi,1/R    * 
+*/
+/**               DQ(1-5)   :  deviations from reference trajectory      
+**/
+/**                             on x,y,theta,phi,1/R       (plane)       
+**/
+/**                             or Phi,z,theta,beta,1/R    (cylinder)    
+**/
+/*               WG(1-15)  :  weight matrix on these parameters         * 
+*/
+/*                                                                      * 
+*/
+/*   Output  :   PAR(1-6)  :  parameters with the new type              * 
+*/
+/*               DQ(1-5)   :  deviations from reference trajectory      * 
+*/
+/*               WG(1-15)  :  weight matrix on these parameters         * 
+*/
+/************************************************************************/
+
+ void TrigInDetSctKFitter::tswtch(long *ityp, double *par, double *wg)
+{
+    double cosb, cosf, sinf, x, y, z, rcosb, tanth, d11, d21, 
+           d12, d22, d42, d41, w11, w12, w13, w14, w15, w21, w22, capphi, 
+           rad, phi;
+
+    /* Parameter adjustments */
+    --wg;
+    --par;
+
+    /* Function Body */
+    if (*ityp == 1) {
+
+/*   transformation of parameters */
+
+	z = par[1];
+	x = par[2];
+	y = par[3];
+	phi = par[5];
+
+	par[1] = sqrt(x*x + y*y); 
+	par[2] = fmod(atan2(y,x)+2*M_PI,2*M_PI);
+	par[3] = z;
+	par[5] = fmod(phi-par[2]+2*M_PI+M_PI, 2*M_PI)-M_PI;
+
+/* * */
+/* *   transformation of deviations */
+/* * */
+/*        RCOSB=PAR(1)*COS(PAR(5)) */
+	
+	tanth = tan(par[4]);
+	cosf = cos(phi);
+	sinf = sin(phi);
+/*        DQQ=(X*DQ(1)+Y*DQ(2))/RCOSB */
+/*        DQ(1)= (-SINF*DQ(1)+COSF*DQ(2))/RCOSB */
+/*        DQ(2)=-DQQ/TANTH */
+/*        DQ(4)=DQ(4)-PAR(6)*DQQ-DQ(1) */
+
+/*   transformation of weight matrix  x,y,phi -> Phi,z,phi */
+
+	d11 = -y;
+	d21 = x;
+	d12 = -tanth * cosf;
+	d22 = -tanth * sinf;
+	d42 = -tanth * par[6];
+
+	w11 = d11 * wg[1] + d21 * wg[2];
+	w12 = d11 * wg[2] + d21 * wg[3];
+	w13 = d11 * wg[4] + d21 * wg[5];
+	w14 = d11 * wg[7] + d21 * wg[8];
+	w15 = d11 * wg[11] + d21 * wg[12];
+	w21 = d12 * wg[1] + d22 * wg[2] + d42 * wg[7];
+	w22 = d12 * wg[2] + d22 * wg[3] + d42 * wg[8];
+	wg[5] = d12 * wg[4] + d22 * wg[5] + d42 * wg[9];
+	wg[8] = d12 * wg[7] + d22 * wg[8] + d42 * wg[10];
+	wg[12] = d12 * wg[11] + d22 * wg[12] + d42 * wg[14];
+
+	wg[1] = w11 * d11 + w12 * d21;
+	wg[2] = w21 * d11 + w22 * d21;
+	wg[3] = w21 * d12 + w22 * d22 + wg[8] * d42;
+
+/*   transformation  Phi,phi -> Phi,beta */
+
+	wg[1] = wg[1] + w14 * 2. + wg[10];
+	wg[2] += wg[8];
+	wg[4] = w13 + wg[9];
+	wg[7] = w14 + wg[10];
+	wg[11] = w15 + wg[14];
+
+/*   transformation from 'CYLI' to 'PLAN' -------------------------- */
+
+    } else {
+
+/*   transformation of parameters */
+
+	rad = par[1];
+	capphi = par[2];
+	cosb = cos(par[5]);
+
+	par[1] = par[3];
+	par[2] = rad * cos(capphi);
+	par[3] = rad * sin(capphi);
+	par[5] = fmod(capphi+par[5]+2.*2*M_PI,2*M_PI);
+	cosf = cos(par[5]);
+	sinf = sin(par[5]);
+	tanth = tan(par[4]);
+/* * */
+/* *   transformation of deviations */
+/* * */
+/*        DQ(4)=DQ(4)-TANTH*PAR(6)*DQ(2)+DQ(1) */
+/*        DQ1= -PAR(3)*DQ(1)-TANTH*COSF*DQ(2) */
+/*        DQ(2)=PAR(2)*DQ(1)-TANTH*SINF*DQ(2) */
+/*        DQ(1)=DQ1 */
+
+/*   transformation of weight matrix  Phi,beta -> Phi,phi */
+
+	wg[1] = wg[1] - wg[7] * 2. + wg[10];
+	wg[2] -= wg[8];
+	wg[4] -= wg[9];
+	wg[7] -= wg[10];
+	wg[11] -= wg[14];
+
+/*   transformation of weight matrix  Phi,z,phi -> x,y,phi */
+
+	rcosb = rad * cosb;
+	d11 = -sinf / rcosb;
+	d12 = cosf / rcosb;
+	double tem = tanth * rcosb;
+	d21 = -par[2] / tem;
+	d22 = -par[3] / tem;
+	tem = par[6] / rcosb;
+	d41 = -par[2] * tem;
+	d42 = -par[3] * tem;
+
+	w11 = d11 * wg[1] + d21 * wg[2] + d41 * wg[7];
+	w12 = d11 * wg[2] + d21 * wg[3] + d41 * wg[8];
+	w13 = d11 * wg[4] + d21 * wg[5] + d41 * wg[9];
+	w14 = d11 * wg[7] + d21 * wg[8] + d41 * wg[10];
+	w15 = d11 * wg[11] + d21 * wg[12] + d41 * wg[14];
+	w21 = d12 * wg[1] + d22 * wg[2] + d42 * wg[7];
+	w22 = d12 * wg[2] + d22 * wg[3] + d42 * wg[8];
+	wg[5] = d12 * wg[4] + d22 * wg[5] + d42 * wg[9];
+	wg[8] = d12 * wg[7] + d22 * wg[8] + d42 * wg[10];
+	wg[12] = d12 * wg[11] + d22 * wg[12] + d42 * wg[14];
+
+	wg[1] = w11 * d11 + w12 * d21 + w14 * d41;
+	wg[2] = w21 * d11 + w22 * d21 + wg[8] * d41;
+	wg[3] = w21 * d12 + w22 * d22 + wg[8] * d42;
+	wg[4] = w13;
+	wg[7] = w14;
+	wg[11] = w15;
+    }
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::txtrpa(double *parami, long *idir, double *radf,
+			double *zmin, double *zmax, double *sinbmx, 
+			long *iopt, double *paramf, double *der, 
+			double *alrphi, long *ierr)
+{
+    /* System generated locals */
+    double r__1;
+
+    double dphimn=0.0001;
+
+    /* Local variables */
+    double alff, beta, fact, radi, dphi, cosb, phii, delt, sinb, 
+           cosf, phif, sinf, rtrk, cdphi, cosbf, ccpsf, dcosf, sinbf, ccpsi, 
+           dsinf, cpsif, rdphi, cpsii, sdphi, rcosb, sphif, cotth, 
+          scpsi, spsif, spsii, aa, xc, yc, xf, yf, zf, rc2, dr2, pph, rrr;
+
+/* ***********************************************************************
+ */
+/*    AIM :                                                             * */
+/*    -----                                                             * 
+*/
+/*    Extrapolate a helix defined by the initial parameters PARAMI      * */
+/*    up to a given cylinder, and compute if requested the derivatives  * */
+/*    of the final parameters w.r.t. the initial ones                   * */
+/*    The computation uses double precision on intermediate variables   * */
+/*    If the variation of phi angle is less than DPHIMN (.0001 in this  * */
+/*    version) the computation is done at first order in 1/R in order   * */
+/*    to avoid rounding errors, especially in the derivatives           * */
+/*                                                                      * */
+/*    Input  :  PARAMI(1-6)   : initial parameters                      * */
+/*                              (r,Phi,z,theta,beta,1/R)                * */
+/*                              with beta = phi-Phi                     * */
+/*              IDIR    :  if  1 : positive extrapolation only          * */
+/*                         if -1 : negative         "                   * */
+/*                         if  0 : extrapolation on both sides          * */
+/*              RADF          : radius of the cylinder                  * */
+/*              ZMIN          : lower z limit of the cylinder           * */
+/*              ZMAX          : upper z limit of the cylinder           * */
+/*              SINBMX        : maximum allowed for |sin(beta)| at the  * */
+/*                              intersection                            * */
+/*              IOPT          : 0 if derivatives not requested          * */
+/*                              1 if derivatives requested              * */
+/*                                                                      * */
+/*    Output :  IERR          : 0 if intersection found                 * */
+/*                              1 if no intersection with the cylinder  * */
+/*                              2 if SINBMX exceeded                    * */
+/*                              3 if intersection outside of z limits   * */
+/*                              4 if 1/Rtr = 0                          * */
+/*              PARAMF(1-6)   : final parameters                        * */
+/*              DER(1-8)      : deriv. of final w.r.t. initial param.   * */
+/*                              DER(1) = d(1/R)/d(1/R)                  * */
+/*                              DER(2) = d(Phi)/d(beta)                 * */
+/*                              DER(3) = d(Phi)/d(1/R)                  * */
+/*                              DER(4) = d(z)/d(theta)                  * */
+/*                              DER(5) = d(z)/d(beta)                   * */
+/*                              DER(6) = d(z)/d(1/R)                    * */
+/*                              DER(7) = d(beta)/d(beta)                * */
+/*                              DER(8) = d(beta)/d(1/R)                 * */
+/*              ALRPHI        : length (in r-phi projection) from start * */
+/*                              to extrapolation, with a sign (positive * */
+/*                              if the extrapolation is towards the     * */
+/*                              direction defined by theta,phi)         * */
+/* ***********************************************************************
+ */
+    /* Parameter adjustments */
+    --der;
+    --paramf;
+    --parami;
+
+    /* Function Body */
+    *ierr = 0;
+
+    if (parami[6] == 0.) {
+	*ierr = 4;
+	return;
+    }
+    radi = parami[1];
+    phii = parami[2];
+    beta = parami[5];
+    cosb = cos(beta);
+    sinb = sin(beta);
+    cotth = 1. / tan(parami[4]);
+    rtrk = 1. / parami[6];
+
+/*  center and squared radius of the projected helix, in a rotated frame 
+*/
+/*  (x-axis through the starting point) */
+    xc = radi - rtrk * sinb;
+    yc = rtrk * cosb;
+    rc2 = xc * xc + yc * yc;
+
+/*  resolution of a second order equation */
+/* Computing 2nd power */
+    r__1 = *radf;
+    rrr = (r__1 * r__1 - rtrk * rtrk - rc2) / (rtrk * 2.);
+    delt = rc2 - rrr * rrr;
+
+/*   intersection exists if DELT > 0 */
+
+    if (delt <= 0.) {
+	*ierr = 1;
+    } else {
+	delt = sqrt(delt);
+
+/*   choose intersection on the same side as the starting point */
+/*   w.r.t. the plane containing the z axis and the axis of the helix */
+
+	sinf = (xc * rrr + yc * delt) / rc2;
+	cosf = (xc * delt - yc * rrr) / rc2;
+	xf = xc + rtrk * sinf;
+	yf = yc - rtrk * cosf;
+	sinbf = (sinf * xf - cosf * yf) / *radf;
+
+/*   exit if beta too large at the intersection */
+	if (fabs(sinbf) > *sinbmx) {
+	    *ierr = 2;
+	} else {
+	    alff = atan2(sinf, cosf);
+	    dphi = fmod(alff - beta + 2*M_PI + M_PI, 2*M_PI) - M_PI;
+	    *alrphi = rtrk * dphi;
+
+/*   select positive or negative extrapolations, or both */
+
+	    if (*alrphi * *idir < 0.) {
+		*ierr = 1;
+		return;
+	    }
+
+/*   switch to approximate expressions if the variation of phi */
+/*   is less than DPHIMN */
+
+/*   "exact" expressions --------------------------------------- */
+
+	    if (fabs(dphi) >= dphimn) {
+
+		zf = parami[3] + cotth * rtrk * dphi;
+
+/*   exit if outside of limits in z,theta,Phi */
+
+		phif = atan2(yf, xf);
+		pph = phif;
+		if (pph < 0.) {
+		    pph += 2*M_PI;
+		}
+		if (zf < *zmin || zf > *zmax) {
+		    *ierr = 3;
+		} else {
+
+/*   final parameters */
+		    paramf[1] = *radf;
+		    paramf[2] = fmod(phii + phif + 2*M_PI, 2*M_PI);
+		    paramf[3] = zf;
+		    paramf[4] = parami[4];
+		    paramf[5] = fmod(alff - phif + 2*M_PI + M_PI, 2*M_PI) - M_PI;
+		    paramf[6] = parami[6];
+
+/*   computation of derivatives --------- */
+
+		    if (*iopt == 1) {
+			cosbf = sqrt(1. - sinbf*sinbf);
+
+/*  CCPSI = RC*cos(cap.psi) ; SCPSI = RC*sin(cap.psi)     (initial point) */
+/*  CCPSF = RC*cos(cap.psi) ; SCPSF = RC*sin(cap.psi)     (final point) */
+			ccpsi = radi - rtrk * sinb;
+			scpsi = rtrk * cosb;
+			ccpsf = *radf - rtrk * sinbf;
+			
+
+/*  CPSII = sgn*RC*cos(psi) ; SPSII = sgn*RC*sin(psi)     (initial point) */
+/*  CPSIF = sgn*RC*cos(psi) ; SPSIF = sgn*RC*sin(psi)     (final point) */
+			cpsii = rtrk - radi * sinb;
+			spsii = -radi * cosb;
+			cpsif = rtrk - *radf * sinbf;
+			spsif = -(*radf) * cosbf;
+
+			sdphi = sin(dphi);
+			cdphi = cos(dphi);
+
+			der[1] = 0.;
+			fact = -rtrk / spsif;
+			der[2] = sdphi * fact;
+			der[3] = fact * rtrk * (1. - cdphi);
+			der[4] = -rtrk * dphi * (cotth * cotth + 1.);
+			der[5] = rtrk * cotth * (*radf * ccpsf * spsii / 
+						 spsif - radi * ccpsi) / rc2;
+			der[6] = rtrk * rtrk * cotth * (-dphi + sinbf / cosbf 
+				- (radi * scpsi + *radf * ccpsf * cpsii / 
+				   spsif) / rc2);
+			der[7] = spsii / spsif;
+			der[8] = rtrk * (cpsif - cpsii) / spsif;
+		    }
+		}
+
+/*   approximation at first order in 1/R --------------------
+------ */
+
+	    } else {
+
+		dr2 = *radf * *radf - radi * radi;
+		rcosb = radi * cosb;
+		aa = 1. - radi * sinb / rtrk;
+		delt = rcosb * rcosb + aa * dr2;
+/*   exit if no solution */
+		if (delt <= 0.) {
+		    *ierr = 1;
+		} else {
+		    rdphi = (sqrt(delt) - rcosb) / aa;
+		    dphi = rdphi / rtrk;
+		    dcosf = -sinb - cosb * .5 * dphi;
+		    cosf = cosb + dcosf * dphi;
+		    yf = -rdphi * dcosf;
+		    dsinf = cosb - sinb * .5 * dphi;
+		    sinf = sinb + dsinf * dphi;
+		    xf = radi + rdphi * dsinf;
+		    sinbf = (sinf * xf - cosf * yf) / *radf;
+		    zf = parami[3] + cotth * rdphi;
+
+/*   exit if outside of limits in z,theta,Phi */
+
+		    phif = atan2(yf, xf);
+		    pph = phif;
+		    if (pph < 0.) {
+			pph += 2*M_PI;
+		    }
+		    if (zf < *zmin || zf > *zmax) {
+			*ierr = 3;
+		    } else {
+			paramf[1] = *radf;
+			phif = atan2(yf, xf);
+			paramf[2] = fmod(parami[2] + phif + 2*M_PI, 2*M_PI);
+			paramf[3] = zf;
+			paramf[4] = parami[4];
+			paramf[5] = parami[5] + dphi - phif;
+			paramf[6] = parami[6];
+
+/*   Computation of derivatives -------------- */
+
+			if (*iopt == 1) {
+			    cosbf = sqrt(1. - sinbf * sinbf);
+			    sphif = yf / *radf;
+
+			    der[1] = 0.;
+			    der[2] = rdphi / (*radf * cosbf);
+			    der[3] = rdphi * .5 * der[2];
+			    der[4] = -rdphi * (cotth * cotth + 1.);
+			    der[5] = radi * cotth * sphif / cosbf;
+			    der[6] = rdphi * .5 * der[5];
+			    der[7] = radi * cosb / (*radf * cosbf);
+			    der[8] = rdphi * .5 * (der[7] + 1.);
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::txxpla(double *parami, long *idir, double *zf, double *rmin, 
+			double *rmax, long *iopt, double *paramf, 
+			double *der, double *alrphi, long *ierr)
+{
+ 
+    /* Local variables */
+    double dphi, rtrk, cosf0, cosf1, sinf0, sinf1, dcosf, dsinf, 
+           rdphi, tanth, r1, x1, y1, ct2inv, xc, yc, dz, phi1;
+
+/* ***********************************************************************
+ */
+/*    AIM :                                                             * */
+/*    -----                                                             * 
+*/
+/*    extrapolate a helix defined by the initial parameters PARAMI      * */
+/*    up to a given z-plane, and compute the derivatives of the         * */
+/*    final parameters w.r.t. the initial ones                          * */
+/*                                                                      * */
+/*    The computation uses double precision on intermediate variables   * */
+/*    If the variation of phi angle is less than DPHIMN (.0001 in this  * */
+/*    version) the computation is done at first order in 1/R in order   * */
+/*    to avoid rounding errors in the derivatives                       * */
+/*                                                                      * */
+/*    Input  :  PARAMI(1-6)   : initial parameters                      * */
+/*                              (z,x,y,theta,phi,1/R)                   * */
+/*              ZF            : z of the final plane                    * */
+/*              IDIR    :  if  1 : positive extrapolation only          * */
+/*                         if -1 : negative         "                   * */
+/*                         if  0 : extrapolation on both sides          * */
+/*              RMIN          : lower limit of r on the plane           * */
+/*              RMAX          : upper limit of r on the plane           * */
+/*              IOPT          : 0 if derivatives not requested          * */
+/*                              1 if derivatives requested              * */
+/*                                                                      * */
+/*    Output :  IERR          : 0 if OK                                 * */
+/*                              1 if no intersection found              * */
+/*                              3 if intersection outside of limits     * */
+/*              PARAMF(1-6)   : final parameters                        * */
+/*              DER(1-8)      : deriv. of final w.r.t. initial param.   * */
+/*                              DER(1) = d(x)/d(theta)                  * */
+/*                              DER(2) = d(x)/d(phi)                    * */
+/*                              DER(3) = d(x)/d(1/R)                    * */
+/*                              DER(4) = d(y)/d(theta)                  * */
+/*                              DER(5) = d(y)/d(phi)                    * */
+/*                              DER(6) = d(y)/d(1/R)                    * */
+/*                              DER(7) = d(phi)/d(theta)                * */
+/*                              DER(8) = d(phi)/d(1/R)                  * */
+/*              ALRPHI        : length (in r-phi projection) from start * */
+/*                              to extrapolation, with a sign (positive * */
+/*                              if the extrapolation is towards the     * */
+/*                              direction defined by theta,phi)         * */
+/* ***********************************************************************
+ */
+/*      REAL RZSURF,ZRMIN,ZRMAX,THXMIN,THXMAX,PHYMIN,PHYMAX */
+
+    /* Parameter adjustments */
+    --der;
+    --paramf;
+    --parami;
+
+    /* Function Body */
+    *ierr = 0;
+
+    dz = *zf - parami[1];
+    tanth = tan(parami[4]);
+    rdphi = dz * tanth;
+
+/*   select positive or negative extrapolation, or both */
+    if (rdphi * *idir < 0.) {
+	*ierr = 1;
+    } else {
+	*alrphi = rdphi;
+
+/*   x,y coordinates of intersection */
+	rtrk = 1. / parami[6];
+	cosf0 = cos((double) parami[5]);
+	sinf0 = sin((double) parami[5]);
+	xc = parami[2] - rtrk * sinf0;
+	yc = parami[3] + rtrk * cosf0;
+	dphi = parami[6] * rdphi;
+	phi1 = fmod(parami[5] + dphi, 2*M_PI);
+	cosf1 = cos(phi1);
+	sinf1 = sin(phi1);
+	x1 = xc + rtrk * sinf1;
+	y1 = yc - rtrk * cosf1;
+	r1 = sqrt(x1 * x1 + y1 * y1);
+
+/*   intersection outside of limits in r,x,y */
+	if (r1 < *rmin || r1 > *rmax) {
+	    *ierr = 3;
+
+/*   parameters at the intersection */
+	} else {
+	    paramf[1] = *zf;
+	    paramf[2] = x1;
+	    paramf[3] = y1;
+	    paramf[4] = parami[4];
+	    paramf[5] = phi1;
+	    if (paramf[5] < 0.) paramf[5] += 2*M_PI;
+	    paramf[6] = parami[6];
+
+/*   computation of derivatives ----------------------------------- */
+
+	    if (*iopt == 1) {
+		ct2inv = (tanth * tanth + 1.) * dz;
+		der[1] = ct2inv * cosf1;
+		der[4] = ct2inv * sinf1;
+		der[7] = parami[6] * ct2inv;
+		der[8] = rdphi;
+
+/*   "exact" formulae if |DPHI| > DPHIMN */
+		if (fabs(dphi) >= 1e-4) {
+		    dcosf = cosf1 - cosf0;
+		    dsinf = sinf1 - sinf0;
+		    der[2] = rtrk * dcosf;
+		    der[3] = rtrk * rtrk * (dphi * cosf1 - dsinf);
+		    der[5] = rtrk * dsinf;
+		    der[6] = rtrk * rtrk * (dphi * sinf1 + dcosf);
+
+/*   first order in 1/R if |DPHI| < DPHIMN */
+		} else {
+		    der[2] = -rdphi * sinf0;
+		    der[3] = rdphi * .5 * der[2];
+		    der[5] = rdphi * cosf0;
+		    der[6] = rdphi * .5 * der[5];
+		}
+	    }
+	}
+    }
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+/* *******************************************************************
+                                                                   
+              TMSCAT (float *SINTH,float *PINV,float *XRL,float *WG,float *dir)
+                                                                     
+							   
+ * Transformation of weight matrix to account for multiple scatt.    *
+*   at a given point                                                  *
+*                                                                     *
+*   Input  :  SINTH  :  sin(theta)                                    *
+*             PINV   :  1/p                                           *
+*             XRL    :  number of rad. lengths crossed at this point  *
+*             WG     :  initial weight matrix                         *
+*             dir    :  direction of update (+1. = add a hit,         *
+*                                            -1. = subtract a hit)    *
+*                                                                     *
+*   Output :  WG     :  final weight matrix                           *
+*                                                                     *
+***********************************************************************
+*/
+
+void TrigInDetSctKFitter::tmscat(double *sinth, double *pinv, double *xrl, double *wg, 
+			double *dir)
+{  //local variable
+
+      double  th2, xtt, xtb, xbb, q, ubb, utb, utt, s13, s14, s23, s24;
+      double  s33, s34, s43, s44, s53, s54, wg4, wg5,wg9, wg13; 
+      
+      /* Parameter adjustments*/
+      
+      --wg;
+/*
+*   mean squared scattering angle in a direction perpendicular to
+*   the trajectory (assuming large ratio momentum/mass)
+*/
+      th2 = 0.0136*(*pinv)*(1.+0.038*log(*xrl));
+      th2 = fabs(th2*th2*(*xrl))*(*dir);
+    
+     // matrix (2x2)  X = (cov.m.s.(theta,beta))**(-1) + TH2 * WG(theta,beta)
+      xtt = 1.+ th2*wg[6];
+      xtb = th2*wg[9];
+      xbb = (*sinth)*(*sinth) + th2*wg[10];
+
+     //matrix  U = TH2 * X**(-1)
+      q=th2/(xbb*xtt - xtb*xtb);
+      ubb=q*xtt;
+      utb=-q*xtb;
+      utt=q*xbb;
+
+      //computation of  WG - WG * (U ext. to 5x5) * WG
+
+      s13    = -wg[ 4]*utt - wg[ 7]*utb;
+      s14    = -wg[ 4]*utb - wg[ 7]*ubb;
+      s23    = -wg[ 5]*utt - wg[ 8]*utb;
+      s24    = -wg[ 5]*utb - wg[ 8]*ubb;
+      s53    = -wg[13]*utt - wg[14]*utb;
+      s54    = -wg[13]*utb - wg[14]*ubb;
+      wg[ 1] =  wg[ 1] + s13*wg[ 4] + s14*wg[ 7];
+      wg[ 2] =  wg[ 2] + s13*wg[ 5] + s14*wg[ 8];
+      wg[11] =  wg[11] + s13*wg[13] + s14*wg[14];
+      wg[ 3] =  wg[ 3] + s23*wg[ 5] + s24*wg[ 8];
+      wg[12] =  wg[12] + s23*wg[13] + s24*wg[14];
+      wg[15] =  wg[15] + s53*wg[13] + s54*wg[14];
+
+      s33    =  1.-wg[6]*utt-wg[ 9]*utb;
+      s34    =    -wg[6]*utb-wg[ 9]*ubb;
+      s43    =    -wg[9]*utt-wg[10]*utb;
+      s44    =  1.-wg[9]*utb-wg[10]*ubb;
+      wg4    =  s33*wg[ 4] + s34*wg[ 7];
+      wg5    =  s33*wg[ 5] + s34*wg[ 8];
+      wg[ 6] =  s33*wg[ 6] + s34*wg[ 9];
+      wg9    =  s33*wg[ 9] + s34*wg[10];
+      wg13   =  s33*wg[13] + s34*wg[14];
+      wg[ 7] =  s43*wg[ 4] + s44*wg[ 7];
+      wg[ 8] =  s43*wg[ 5] + s44*wg[ 8];
+      wg[10] =  s43*wg[ 9] + s44*wg[10];
+      wg[14] =  s43*wg[13] + s44*wg[14];
+      wg[ 4] =  wg4;
+      wg[ 5] =  wg5;
+      wg[ 9] =  wg9;
+      wg[13] =  wg13;
+
+      return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+// To add the energy loss effect in:-----------------------------------------
+//									                                        *
+// Input: x0  -- the material budget associated at a point in the unit of   *
+//               radiation lengths;                                         *
+//        dir -- direction of the reconstruction process                    *
+//               (1. for going inwards, -1. for going outwards)             *
+//    									                                    *
+// Input and output: par6   -- the 6th track parameter, i.e. 1/Rtr          *
+//    		     wg[15] -- weight matrix			                	    *
+//    									                                    *
+// Authors: S. Qian							                                *
+//									                                        *
+// Date: Nov 16, 1999							                            *
+//--------------------------------------------------------------------------*
+
+void TrigInDetSctKFitter::add_E_loss(double *x0, double *dir, double *par6, double *wg) {
+
+  double q55, tem;
+  q55 = (*dir)*(*par6)*(*par6)*(*x0)*(0.415-0.744*(*x0));
+  if(q55==0.) return;
+  tem = 1./q55+wg[14];
+  if(tem==0.) {return;} else {tem=1./tem;}
+  *par6 *= (1. - (*dir)*(*x0)*(1.-0.5*(*x0)));
+  wg[0] -= tem*wg[10]*wg[10];
+  wg[1] -= tem*wg[10]*wg[11];
+  wg[2] -= tem*wg[11]*wg[11];
+  wg[3] -= tem*wg[10]*wg[12];
+  wg[4] -= tem*wg[11]*wg[12];
+  wg[5] -= tem*wg[12]*wg[12];
+  wg[6] -= tem*wg[10]*wg[13];
+  wg[7] -= tem*wg[11]*wg[13];
+  wg[8] -= tem*wg[12]*wg[13];
+  wg[9] -= tem*wg[13]*wg[13];
+  wg[10] -= tem*wg[10]*wg[14];
+  wg[11] -= tem*wg[11]*wg[14];
+  wg[12] -= tem*wg[12]*wg[14];
+  wg[13] -= tem*wg[13]*wg[14];
+  wg[14] -= tem*wg[14]*wg[14];
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+ void TrigInDetSctKFitter::trf2xy(long *idir, double *r, double *phi, double *wm) const
+{
+  /* transform weight matrix from (r,phi) to (x.y) (when idir= 1)
+                             from (x,y) to (r,phi) (when idir= -1)
+			     
+     input: idir --- direction of the tranformation
+            r    --- in (cm)
+	    phi  --- in (radian)
+     input and output: wm (15)
+
+     Auther: Sijin Qian, 4/1994
+  */
+
+  double d11, d21, d12, d22, wm1[12];
+
+  // d21 = sin(*phi) * pow((-(*r)), ((1-(*idir))/2));
+  // d22 = d11/r**(idir)
+
+  d11 = cos(*phi);
+  if((*idir) > 0) {
+    d21 = sin(*phi);
+    d22 = d11/(*r);
+  } else {
+    d21 = - sin(*phi) * (*r);
+    d22 = d11*(*r);
+  }
+  d12 = -d21/(*r);
+
+  for (long i=0; i<12; i++) {wm1[i]=wm[i];}
+
+  wm[ 0] = d11*d11*wm1[ 0] +        2.*d11*d12*wm1[1] + d12*d12*wm1[2];
+  wm[ 1] = d11*d21*wm1[ 0] + (d12*d21+d11*d22)*wm1[1] + d12*d22*wm1[2];
+  wm[ 2] = d21*d21*wm1[ 0] +        2.*d21*d22*wm1[1] + d22*d22*wm1[2];
+  wm[ 3] =     d11*wm1[ 3] +               d12*wm1[4];
+  wm[ 4] =     d21*wm1[ 3] +               d22*wm1[4];
+  wm[ 6] =     d11*wm1[ 6] +               d12*wm1[7];
+  wm[ 7] =     d21*wm1[ 6] +               d22*wm1[7];
+  wm[10] =     d11*wm1[10] +               d12*wm1[11];
+  wm[11] =     d21*wm1[10] +               d22*wm1[11];
+
+  return ;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::taddpt(double *df, double *dz,   double *wff,   double *wzz, 
+		   double *dp, double *wotr, double *achi2, long *ierr)
+{
+    double r__1, r__2;
+    long ier;
+
+/* ------------------------------------------------- */
+
+/* Subroutine for adding a point to a track */
+
+/*Input           : df, dz    -- Deviation of first two of 5 track parameters*/
+/*                  wff, wzz  -- Weight on the two parameters */
+
+/* Input and output : wotr(1:15) -- weight matrix of parameters */
+
+/* Output           : dp(1:5)   -- Adjustment on track parameters */
+/*                    achi2     -- Incremental of Chi2 by adding this point*/
+/*                    ierr      -- error code (0 = OK) */
+/*                                            (1 = Chi2 increase too much)*/
+/*                                            (2 = error in TSOLVE) */
+/* ------------------------------------------------- */
+
+    /* Parameter adjustments */
+    --wotr;
+    --dp;
+
+    /* Function Body */
+
+/* To add the weight of the point to the weght matrix */
+/*   and to solve the linear system */
+
+    wotr[1] += *wff;
+    wotr[3] += *wzz;
+		
+	if (wotr[1] <= 0. || wotr[3] <= 0.) {
+	*ierr = 3;
+	goto L20;
+    }
+    r__1 = *wff * *df;
+    r__2 = *wzz * *dz;
+    tsolve(&wotr[1], &r__1, &r__2, &dp[1], &ier);
+    
+	if (ier != 0) {
+	*ierr = 2;
+	goto L20;
+    }
+    if (*wff < 0.) {
+	return;
+    }
+
+/* Increase of chi2 */
+
+    r__1 = *df - dp[1];
+    r__2 = *dz - dp[2];
+
+    *achi2 =
+
+/* Contribution of the added point */
+ 
+      *wff * (r__1 * r__1) + *wzz * (r__2 * r__2) 
+
+/* Variation for previous ensembled points */
+
+      + (wotr[1] - *wff) * (dp[1] * dp[1]) 
+      + (2. *  wotr[2] * dp[1] + (wotr[3] - *wzz) * dp[2]) * dp[2] 
+      + (2. * (wotr[4] * dp[1] + wotr[5] * dp[2]) + wotr[6] * dp[3]) * dp[3] 
+      + (2. * (wotr[7] * dp[1] + wotr[8] * dp[2]  + wotr[9] * dp[3]) 
+	                                         + wotr[10] * dp[4]) * dp[4] 
+      + (2. * (wotr[11] * dp[1]  + wotr[12] * dp[2] + wotr[13] * dp[3] + 
+	       wotr[14] * dp[4]) + wotr[15] * dp[5]) * dp[5];
+
+/* chi2 cut */
+
+    *ierr = (*achi2 <= maxDChi2[paramset]) ? 0 : 1;
+	
+/* In the failure case, restore the previous weight matrix */
+
+L20:
+	
+/*      IF(IERR.NE.0.AND.WFF.GT.0.) THEN */
+    if (*ierr != 0) {
+	wotr[1] -= *wff;
+	wotr[3] -= *wzz;
+    }
+
+    return;
+}
+
+
+
+//-------------------------------------------------------------------------
+
+
+
+void TrigInDetSctKFitter::tsolve(double *w, double *vy, double *vz, double *d, long *ier)
+{
+    /* Local variables */
+    double  q, r11, r12, r13, r14, r22, r23, r24, r33, r34, r44, tem, 
+            piv3, piv4, piv5;
+
+/* ---------------------------------------------------------- */
+/* Subroutine to solve a linear system */
+/* ---------------------------------------------------------- */
+
+    /* Parameter adjustments */
+    --d;
+    --w;
+
+    /* Function Body */
+    *ier = 0;
+    piv5 = 1. / w[15];
+    q = w[11] * piv5;
+    r11 = w[1] - q * w[11];
+    r12 = w[2] - q * w[12];
+    r13 = w[4] - q * w[13];
+    r14 = w[7] - q * w[14];
+    q = w[12] * piv5;
+    r22 = w[3] - q * w[12];
+    r23 = w[5] - q * w[13];
+    r24 = w[8] - q * w[14];
+    q = w[13] * piv5;
+    r33 = w[6] - q * w[13];
+    r34 = w[9] - q * w[14];
+    r44 = w[10] - w[14] * w[14] * piv5;
+    if (r44 == 0.) {
+	*ier = 1;
+	return;
+    }
+    piv4 = 1. / r44;
+    q = r14 * piv4;
+    r11 -= q * r14;
+    r12 -= q * r24;
+    r13 -= q * r34;
+    q = r24 * piv4;
+    r22 -= q * r24;
+    r23 -= q * r34;
+    r33 -= r34 * r34 * piv4;
+    if (r33 == 0.) {
+	*ier = 1;
+	return;
+    }
+    piv3 = 1. / r33;
+    q = r13 * piv3;
+    r11 -= q * r13;
+    r12 -= q * r23;
+    r22 -= r23 * r23 * piv3;
+    tem = r11 * r22 - r12 * r12;
+    if (tem == 0.) {
+	*ier = 1;
+	return;
+    }
+    q = 1. / tem;
+    d[1] = q * ( r22 * *vy - r12 * *vz);
+    d[2] = q * (-r12 * *vy + r11 * *vz);
+    d[3] = -piv3 * (r13 * d[1] + r23 * d[2]);
+    d[4] = -piv4 * (r14 * d[1] + r24 * d[2] + r34 * d[3]);
+    d[5] = -piv5 * (w[11] * d[1] + w[12] * d[2] + w[13] * d[3] + w[14] * d[4]);
+
+    return;
+}
+
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetTrackFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetTrackFitter.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..f4856b4d1390ad1ec7f94ef3583f7082467c5fcb
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigInDetTrackFitter.cxx
@@ -0,0 +1,1110 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigInDetTrackFitter tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 01.09.2005 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include <cmath>
+#include <iostream>
+#include "StoreGate/StoreGateSvc.h" 
+#include "GaudiKernel/ToolFactory.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "StoreGate/DataHandle.h"
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+#include "TrigInDetEvent/TrigInDetTrackCollection.h"
+
+#include "TrkSurfaces/Surface.h"
+#include "TrkSurfaces/TrapezoidBounds.h"
+#include "TrkParameters/TrackParameters.h"
+
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+
+#include "InDetPrepRawData/SCT_Cluster.h"
+#include "InDetPrepRawData/PixelCluster.h"
+#include "TrigTimeAlgs/TrigTimerSvc.h"
+
+#include "TrigInDetToolInterfaces/ITrigInDetTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetTrackFitter.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+
+TrigInDetTrackFitter::TrigInDetTrackFitter(const std::string& t, 
+					   const std::string& n,
+					   const IInterface*  p ): AthAlgTool(t,n,p),
+								   m_MagFieldSvc("AtlasFieldSvc",this->name()),
+								   m_trackMaker("TrigDkfTrackMakerTool")
+{
+  declareInterface< ITrigInDetTrackFitter >( this );
+  
+  declareProperty( "AthenaFieldService", m_MagFieldSvc, "AlasFieldService");
+  declareProperty( "doMultScattering", m_doMultScatt = true);
+  declareProperty( "doBremmCorrection", m_doBremm=false);  
+  declareProperty( "Chi2Cut", m_DChi2 = 1000.0);
+  declareProperty( "OfflineClusters", m_offlineClusters = true);
+}
+
+StatusCode TrigInDetTrackFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+  
+	ATH_MSG_INFO("Using Athena magnetic field service");
+	sc = m_MagFieldSvc.retrieve();
+	if(sc.isFailure()) 
+	{
+		ATH_MSG_ERROR("Unable to retrieve Athena MagFieldService");
+		return StatusCode::FAILURE;
+	}
+  sc=m_trackMaker.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve "<<m_trackMaker);
+      return sc;
+    }
+
+  ITrigTimerSvc* timerSvc;
+  StatusCode scTime = service( "TrigTimerSvc", timerSvc);
+  if( scTime.isFailure() ) {
+    ATH_MSG_INFO("Unable to locate Service TrigTimerSvc ");
+    m_timers = false;
+  } 
+  else{
+    m_timers = true;  
+  }
+//   add some timers:
+//
+  if ( m_timers ) {
+    m_timer[0] = timerSvc->addItem("CreateNodes");
+    m_timer[1] = timerSvc->addItem("ForwardFilter");
+    m_timer[2] = timerSvc->addItem("Smoother");
+    m_timer[3] = timerSvc->addItem("TrigTrackPars");
+    m_timer[4] = timerSvc->addItem("CleanUp");
+  }
+
+  m_fitStats.clear();
+  for(int i=0;i<13;i++) m_fitStats.push_back(FitStatStruct(i));
+  m_algorithmId=0;
+  ATH_MSG_INFO("TrigInDetTrackFitter constructed");
+  return sc;
+}
+
+StatusCode TrigInDetTrackFitter::finalize()
+{
+  MsgStream log(msgSvc(), name());
+  log << MSG::INFO <<"=============================================================="<<endreq ;
+  log << MSG::INFO <<"TrigInDetTrackFitter::finalize() - LVL2 Track fit Statistics: "<<endreq ;
+  for(std::vector<FitStatStruct>::iterator it=m_fitStats.begin();it!=m_fitStats.end();++it) {
+    if((*it).m_nTracksTotal==0) continue;
+    log << MSG::INFO <<"Algorithm Id="<<(*it).m_algorithmId<<" N tracks = "<<(*it).m_nTracksTotal<<endreq ;
+    log << MSG::INFO <<"Problems detected: "<<endreq ;
+    log << MSG::INFO <<"Unresolved spacepoints :"<<(*it).m_fitErrors[0]<<endreq ;
+    log << MSG::INFO <<"Extrapolator divergence:"<<(*it).m_fitErrors[1]<<endreq ;
+    log << MSG::INFO <<"pT falls below 200 MeV :"<<(*it).m_fitErrors[2]<<endreq ;
+  }
+  log << MSG::INFO <<"=============================================================="<<endreq ;
+  m_fitStats.clear();
+  StatusCode sc = AlgTool::finalize(); 
+  return sc;
+}
+
+void TrigInDetTrackFitter::m_getMagneticField(double r[3],double* B)
+{
+  B[0]=0.0;B[1]=0.0;B[2]=0.0;
+	double field[3];
+	m_MagFieldSvc->getField(r,field);//field is returned in kT
+	for(int i=0;i<3;i++) B[i]=field[i]/Gaudi::Units::kilogauss;//convert to kG
+}
+
+void TrigInDetTrackFitter::correctScale(Trk::TrkTrackState* pTS) {
+
+  double Rf[5];
+  double Gf[5][5];
+  int i,j;
+
+  for(i=0;i<4;i++) Rf[i] = pTS->m_getTrackState(i);
+  Rf[4] = 0.001*pTS->m_getTrackState(4);
+
+  for(i=0;i<4;i++)
+    for(j=0;j<4;j++) Gf[i][j] = pTS->m_getTrackCovariance(i,j);
+
+  Gf[0][4] = Gf[4][0] = pTS->m_getTrackCovariance(0,4)/1000.0;
+  Gf[1][4] = Gf[4][1] = pTS->m_getTrackCovariance(1,4)/1000.0;
+  Gf[2][4] = Gf[4][2] = pTS->m_getTrackCovariance(2,4)/1000.0;
+  Gf[3][4] = Gf[4][3] = pTS->m_getTrackCovariance(3,4)/1000.0;
+  Gf[4][4] = pTS->m_getTrackCovariance(4,4)/1000000.0;
+
+  pTS->m_setTrackState(Rf);
+  pTS->m_setTrackCovariance(Gf);
+}
+
+Trk::TrkTrackState* TrigInDetTrackFitter::m_extrapolate(Trk::TrkTrackState* pTS, 
+							Trk::TrkPlanarSurface* pSB,
+							Trk::TrkPlanarSurface* pSE)
+{
+  const double C=0.02999975/1000.0;//using GeV internally 
+  const double minStep=30.0;
+	    
+  double J[5][5],Rf[5],AG[5][5],Gi[5][5],Gf[5][5],A[5][5];
+  int i,j,m;
+
+  bool samePlane=false;
+
+  if(pSB!=NULL)
+    {   
+      double diff=0.0;
+      for(i=0;i<4;i++) diff+=fabs(pSE->m_getPar(i)-pSB->m_getPar(i));
+      if(diff<1e-5) {
+	samePlane=true;	
+	(m_fitStats[m_algorithmId]).m_fitErrors[0]++;
+	//std::cout<<"Starting plane and target plane are the same !"<<std::endl;
+      }
+    }
+
+  if(!samePlane) {
+
+    double gP[3],gPi[3],lP[3],gV[3],a,b,c,s,J0[7][5],descr,CQ,Ac,Av,Cc;
+    double V[3],P[3],M[3][3],D[4],Jm[7][7],
+      J1[5][7],gB[3],gBi[3],gBf[3],dBds[3],Buf[5][7],DVx,DVy,DVz;
+    int nStep,nStepMax;
+    double sl,ds,path=0.0;
+
+    //m_numericalJacobian(pTS,pSB,pSE,J);
+    double sint,cost,sinf,cosf;
+    sint=sin(pTS->m_getTrackState(3));cosf=cos(pTS->m_getTrackState(2));
+    sinf=sin(pTS->m_getTrackState(2));cost=cos(pTS->m_getTrackState(3));
+    gV[0]=sint*cosf;gV[1]=sint*sinf;gV[2]=cost;CQ=C*pTS->m_getTrackState(4);
+
+    memset(&J0[0][0],0,sizeof(J0));
+
+    if(pSB!=NULL)
+      {    
+	double L[3][3];
+	lP[0]=pTS->m_getTrackState(0);lP[1]=pTS->m_getTrackState(1);lP[2]=0.0;
+	pSB->m_transformPointToGlobal(lP,gP);
+	for(i=0;i<3;i++) for(j=0;j<3;j++) L[i][j]=pSB->m_getInvRotMatrix(i,j);
+	
+	J0[0][0]=L[0][0];J0[0][1]=L[0][1];
+	J0[1][0]=L[1][0];J0[1][1]=L[1][1];
+	J0[2][0]=L[2][0];J0[2][1]=L[2][1];
+	J0[3][2]=-sinf*sint;J0[3][3]=cosf*cost;
+	J0[4][2]= cosf*sint;J0[4][3]=sinf*cost;
+	J0[5][3]=-sint;
+	J0[6][4]=1.0;
+      }
+    else
+      {
+	gP[0]=-pTS->m_getTrackState(0)*sinf;
+	gP[1]= pTS->m_getTrackState(0)*cosf;
+	gP[2]= pTS->m_getTrackState(1);
+	J0[0][0]=-sinf;J0[0][2]=-pTS->m_getTrackState(0)*cosf;
+	J0[1][0]= cosf;J0[1][2]=-pTS->m_getTrackState(0)*sinf;
+	J0[2][1]=1.0;
+	J0[3][2]=-sinf*sint;J0[3][3]=cosf*cost;
+	J0[4][2]= cosf*sint;J0[4][3]=sinf*cost;
+	J0[5][3]=-sint;
+	J0[6][4]=1.0;
+      }
+    for(i=0;i<4;i++) D[i]=pSE->m_getPar(i);
+    for(i=0;i<3;i++) gPi[i]=gP[i];
+  
+    m_getMagneticField(gP,gB);
+
+    for(i=0;i<3;i++) gBi[i]=gB[i];
+    
+    c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+    b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+    a=0.5*CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+	      gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+	      gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+
+    descr=b*b-4.0*a*c;
+    
+    if(descr<0.0) 
+      {
+	//      printf("D<0 - extrapolation failed\n");
+	return NULL;
+      }
+    
+    bool useExpansion=true;
+    double ratio = 4*a*c/(b*b);
+    
+    if(fabs(ratio)>0.1) 
+      useExpansion = false;
+    
+    if(useExpansion) {
+      sl=-c/b;
+      sl=sl*(1-a*sl/b);
+    }
+    else {
+      int signb = (b<0.0)?-1:1;
+      sl = (-b+signb*sqrt(descr))/(2*a);
+    }
+
+    if(fabs(sl)<minStep) nStepMax=1;
+    else
+      {
+	nStepMax=(int)(fabs(sl)/minStep)+1;
+      }
+    if((nStepMax<0)||(nStepMax>1000))
+      {
+	return NULL;
+      } 
+    Av=sl*CQ;
+    Ac=0.5*sl*Av;
+    DVx=gV[1]*gB[2]-gV[2]*gB[1];
+    DVy=gV[2]*gB[0]-gV[0]*gB[2];
+    DVz=gV[0]*gB[1]-gV[1]*gB[0];
+    
+    P[0]=gP[0]+gV[0]*sl+Ac*DVx;
+    P[1]=gP[1]+gV[1]*sl+Ac*DVy;
+    P[2]=gP[2]+gV[2]*sl+Ac*DVz;
+    V[0]=gV[0]+Av*DVx;
+    V[1]=gV[1]+Av*DVy;
+    V[2]=gV[2]+Av*DVz;
+    
+    m_getMagneticField(P,gB);
+  
+    for(i=0;i<3;i++) gBf[i]=gB[i];
+    for(i=0;i<3;i++)
+      {
+	dBds[i]=(gBf[i]-gBi[i])/sl;
+	gB[i]=gBi[i];
+      }
+    nStep=nStepMax;path=0.0;
+    while(nStep>0)
+      {
+	c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+	b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+	a=0.5*CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+		  gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+		  gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+	
+	ratio = 4*a*c/(b*b);
+	if(fabs(ratio)>0.1) 
+	  useExpansion = false;
+	else useExpansion = true;
+	
+	if(useExpansion) {
+	  sl=-c/b;
+	  sl=sl*(1-a*sl/b);
+	}
+	else {
+	  descr=b*b-4.0*a*c;
+	  if(descr<0.0) 
+	    {
+	      // printf("D<0 - extrapolation failed\n");
+	      return NULL;
+	    }
+	  int signb = (b<0.0)?-1:1;
+	  sl = (-b+signb*sqrt(descr))/(2*a);
+	}
+
+	ds=sl/nStep;path+=ds;
+	Av=ds*CQ;
+	Ac=0.5*ds*Av;
+	DVx=gV[1]*gB[2]-gV[2]*gB[1];
+	DVy=gV[2]*gB[0]-gV[0]*gB[2];
+	DVz=gV[0]*gB[1]-gV[1]*gB[0];
+	
+	P[0]=gP[0]+gV[0]*ds+Ac*DVx;
+	P[1]=gP[1]+gV[1]*ds+Ac*DVy;
+	P[2]=gP[2]+gV[2]*ds+Ac*DVz;
+	V[0]=gV[0]+Av*DVx;
+	V[1]=gV[1]+Av*DVy;
+	V[2]=gV[2]+Av*DVz;
+	for(i=0;i<3;i++) 
+	  {
+	    gV[i]=V[i];gP[i]=P[i];
+	  }
+	for(i=0;i<3;i++) gB[i]+=dBds[i]*ds;
+	nStep--;
+      }
+    pSE->m_transformPointToLocal(gP,lP);
+    Rf[0]=lP[0];Rf[1]=lP[1];
+    Rf[2]=atan2(V[1],V[0]);
+
+    if(fabs(V[2])>1.0) 
+      {
+	return NULL;
+      }
+
+    Rf[3]=acos(V[2]);
+    Rf[4]=pTS->m_getTrackState(4);
+    
+    gV[0]=sint*cosf;gV[1]=sint*sinf;gV[2]=cost;
+
+    for(i=0;i<4;i++) D[i]=pSE->m_getPar(i);
+    for(i=0;i<3;i++) gP[i]=gPi[i];
+
+    for(i=0;i<3;i++)
+      {
+	gB[i]=0.5*(gBi[i]+gBf[i]);
+      }
+  
+    c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+    b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+    a=CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+	  gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+	  gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+    
+    ratio = 4*a*c/(b*b);
+    if(fabs(ratio)>0.1) 
+      useExpansion = false;
+    else useExpansion = true;
+    
+    if(useExpansion) {
+      s=-c/b;
+      s=s*(1-a*s/b);
+    }
+    else {
+      descr=b*b-4.0*a*c;
+      if(descr<0.0) 
+	{
+	  // printf("D<0 - extrapolation failed\n");
+	  return NULL;
+	}
+      int signb = (b<0.0)?-1:1;
+      s = (-b+signb*sqrt(descr))/(2*a);
+    }
+
+    Av=s*CQ;
+    Ac=0.5*s*Av;
+    Cc=0.5*s*s*C;
+
+    DVx=gV[1]*gB[2]-gV[2]*gB[1];
+    DVy=gV[2]*gB[0]-gV[0]*gB[2];
+    DVz=gV[0]*gB[1]-gV[1]*gB[0];
+    
+    P[0]=gP[0]+gV[0]*s+Ac*DVx;
+    P[1]=gP[1]+gV[1]*s+Ac*DVy;
+    P[2]=gP[2]+gV[2]*s+Ac*DVz;
+
+    V[0]=gV[0]+Av*DVx;V[1]=gV[1]+Av*DVy;V[2]=gV[2]+Av*DVz;
+    
+    pSE->m_transformPointToLocal(P,lP);
+  
+    memset(&Jm[0][0],0,sizeof(Jm));
+    
+    for(i=0;i<3;i++) for(j=0;j<3;j++) M[i][j]=pSE->m_getRotMatrix(i,j);
+    
+    double coeff[3], dadVx,dadVy,dadVz,dadQ,dsdx,dsdy,dsdz,dsdVx,dsdVy,dsdVz,dsdQ;
+    coeff[0]=-c*c/(b*b*b);
+    coeff[1]=c*(1.0+3.0*c*a/(b*b))/(b*b);
+    coeff[2]=-(1.0+2.0*c*a/(b*b))/b;
+    
+    dadVx=0.5*CQ*(-D[1]*gB[2]+D[2]*gB[1]);
+    dadVy=0.5*CQ*( D[0]*gB[2]-D[2]*gB[0]);
+    dadVz=0.5*CQ*(-D[0]*gB[1]+D[1]*gB[0]);
+    dadQ=0.5*C*(D[0]*DVx+D[1]*DVy+D[2]*DVz);
+    
+    dsdx=coeff[2]*D[0];
+    dsdy=coeff[2]*D[1];
+    dsdz=coeff[2]*D[2];
+    dsdVx=coeff[0]*dadVx+coeff[1]*D[0];
+    dsdVy=coeff[0]*dadVy+coeff[1]*D[1];
+    dsdVz=coeff[0]*dadVz+coeff[1]*D[2];
+    dsdQ=coeff[0]*dadQ;
+    
+    Jm[0][0]=1.0+V[0]*dsdx;
+    Jm[0][1]=    V[0]*dsdy;
+    Jm[0][2]=    V[0]*dsdz;
+    
+    Jm[0][3]=  s+V[0]*dsdVx;
+    Jm[0][4]=    V[0]*dsdVy+Ac*gB[2];
+    Jm[0][5]=    V[0]*dsdVz-Ac*gB[1];
+    Jm[0][6]=    V[0]*dsdQ+Cc*DVx;
+
+    Jm[1][0]=    V[1]*dsdx;
+    Jm[1][1]=1.0+V[1]*dsdy;
+    Jm[1][2]=    V[1]*dsdz;
+
+    Jm[1][3]=    V[1]*dsdVx-Ac*gB[2];
+    Jm[1][4]=  s+V[1]*dsdVy;
+    Jm[1][5]=    V[1]*dsdVz+Ac*gB[0];
+    Jm[1][6]=    V[1]*dsdQ+Cc*DVy;
+  
+    Jm[2][0]=    V[2]*dsdx;
+    Jm[2][1]=    V[2]*dsdy;
+    Jm[2][2]=1.0+V[2]*dsdz;
+    Jm[2][3]=    V[2]*dsdVx+Ac*gB[1];
+    Jm[2][4]=    V[2]*dsdVy-Ac*gB[0];
+    Jm[2][5]=  s+V[2]*dsdVz;
+    Jm[2][6]=    V[2]*dsdQ+Cc*DVz;
+
+    Jm[3][0]=dsdx*CQ*DVx;
+    Jm[3][1]=dsdy*CQ*DVx;
+    Jm[3][2]=dsdz*CQ*DVx;
+  
+    Jm[3][3]=1.0+dsdVx*CQ*DVx;
+    Jm[3][4]=CQ*(dsdVy*DVx+s*gB[2]);
+    Jm[3][5]=CQ*(dsdVz*DVx-s*gB[1]);
+  
+    Jm[3][6]=(CQ*dsdQ+C*s)*DVx;
+  
+    Jm[4][0]=dsdx*CQ*DVy;
+    Jm[4][1]=dsdy*CQ*DVy;
+    Jm[4][2]=dsdz*CQ*DVy;
+
+    Jm[4][3]=CQ*(dsdVx*DVy-s*gB[2]);
+    Jm[4][4]=1.0+dsdVy*CQ*DVy;
+    Jm[4][5]=CQ*(dsdVz*DVy+s*gB[0]);
+  
+    Jm[4][6]=(CQ*dsdQ+C*s)*DVy;
+  
+    Jm[5][0]=dsdx*CQ*DVz;
+    Jm[5][1]=dsdy*CQ*DVz;
+    Jm[5][2]=dsdz*CQ*DVz;
+    Jm[5][3]=CQ*(dsdVx*DVz+s*gB[1]);
+    Jm[5][4]=CQ*(dsdVy*DVz-s*gB[0]);
+    Jm[5][5]=1.0+dsdVz*CQ*DVz;
+    Jm[5][6]=(CQ*dsdQ+C*s)*DVz;
+  
+    Jm[6][6]=1.0;
+  
+    memset(&J1[0][0],0,sizeof(J1));
+
+    J1[0][0]=M[0][0];J1[0][1]=M[0][1];J1[0][2]=M[0][2];
+    J1[1][0]=M[1][0];J1[1][1]=M[1][1];J1[1][2]=M[1][2];
+    J1[2][3]=-V[1]/(V[0]*V[0]+V[1]*V[1]);
+    J1[2][4]= V[0]/(V[0]*V[0]+V[1]*V[1]);
+    J1[3][5]=-1.0/sqrt(1-V[2]*V[2]);
+    J1[4][6]=1.0;
+
+    for(i=0;i<7;i++)
+      {
+	for(j=0;j<2;j++)
+	  Buf[j][i]=J1[j][0]*Jm[0][i]+J1[j][1]*Jm[1][i]+J1[j][2]*Jm[2][i];
+	Buf[2][i]=J1[2][3]*Jm[3][i]+J1[2][4]*Jm[4][i];
+	Buf[3][i]=J1[3][5]*Jm[5][i];
+	Buf[4][i]=Jm[6][i];
+      }
+    
+    if(pSB!=NULL)
+      {
+	for(i=0;i<5;i++)
+	  {
+	    J[i][0]=Buf[i][0]*J0[0][0]+Buf[i][1]*J0[1][0]+Buf[i][2]*J0[2][0];
+	    J[i][1]=Buf[i][0]*J0[0][1]+Buf[i][1]*J0[1][1]+Buf[i][2]*J0[2][1];
+	    J[i][2]=Buf[i][3]*J0[3][2]+Buf[i][4]*J0[4][2];
+	    J[i][3]=Buf[i][3]*J0[3][3]+Buf[i][4]*J0[4][3]+Buf[i][5]*J0[5][3];
+	    J[i][4]=Buf[i][6];
+	  }
+      }
+    else
+      {      
+	for(i=0;i<5;i++)
+	  {
+	    J[i][0]=Buf[i][0]*J0[0][0]+Buf[i][1]*J0[1][0];
+	    J[i][1]=Buf[i][2];
+	    J[i][2]=Buf[i][0]*J0[0][2]+Buf[i][1]*J0[1][2]+Buf[i][3]*J0[3][2]+Buf[i][4]*J0[4][2];
+	    J[i][3]=Buf[i][3]*J0[3][3]+Buf[i][4]*J0[4][3]+Buf[i][5]*J0[5][3];
+	    J[i][4]=Buf[i][6];
+	  }
+      }
+  }
+  else {
+    Rf[0]=pTS->m_getTrackState(0);
+    Rf[1]=pTS->m_getTrackState(1);	
+    Rf[2]=pTS->m_getTrackState(2);
+    Rf[3]=pTS->m_getTrackState(3);
+    Rf[4]=pTS->m_getTrackState(4);
+    memset(&J[0][0],0,sizeof(J));
+    for(i=0;i<5;i++) J[i][i]=1.0;
+  }
+
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      AG[i][j]=0.0;for(m=0;m<5;m++) AG[i][j]+=J[i][m]*pTS->m_getTrackCovariance(m,j);
+    }
+  for(i=0;i<5;i++) for(j=i;j<5;j++)
+    {
+      Gf[i][j]=0.0;
+      for(m=0;m<5;m++) Gf[i][j]+=AG[i][m]*J[j][m];
+      Gf[j][i]=Gf[i][j];
+    }
+
+  Trk::TrkTrackState* pTE=new Trk::TrkTrackState(pTS);
+
+  //workaround to keep using existing TrkTrackState code
+  double Rtmp[5];
+
+  for(i=0;i<4;i++) Rtmp[i] = Rf[i];
+  Rtmp[4] = 0.001*Rf[4];//GeV->MeV
+
+  pTE->m_setTrackState(Rtmp);
+  pTE->m_setTrackCovariance(Gf);
+  pTE->m_attachToSurface(pSE);
+
+  pTE->m_applyMaterialEffects();
+
+  pTE->m_setTrackState(Rf);//restore
+
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      Gi[i][j]=pTE->m_getTrackCovariance(i,j);
+    }
+
+  m_matrixInversion5x5(Gi);
+ 
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      A[i][j]=0.0;
+      for(m=0;m<5;m++) A[i][j]+=AG[m][i]*Gi[m][j];
+    }
+  pTE->m_setPreviousState(pTS);
+  pTE->m_setSmootherGain(A);
+
+  return pTE;
+}
+
+void TrigInDetTrackFitter::m_matrixInversion5x5(double a[5][5])
+{
+  /**** 5x5 matrix inversion by Gaussian elimination ****/
+  int i,j,k,l;
+  double factor;
+  double temp[5];
+  double b[5][5];
+  // Set b to I
+
+  memset(&b[0][0],0,sizeof(b));
+  b[0][0]=1.0;b[1][1]=1.0;b[2][2]=1.0;b[3][3]=1.0;b[4][4]=1.0;
+  
+  for(i=0;i<5;i++)
+    {
+      for(j=i+1;j<5;j++)
+	if (fabs(a[i][i])<fabs(a[j][i]))
+	  {
+	    for(l=0;l<5;l++) temp[l]=a[i][l];
+	    for(l=0;l<5;l++) a[i][l]=a[j][l];
+	    for(l=0;l<5;l++) a[j][l]=temp[l];
+	    for(l=0;l<5;l++) temp[l]=b[i][l];
+	    for(l=0;l<5;l++) b[i][l]=b[j][l];
+	    for(l=0;l<5;l++) b[j][l]=temp[l];
+	  }
+      factor=a[i][i];
+      for(j=4;j>-1;j--) 
+	{
+	  b[i][j]/=factor;a[i][j]/=factor;
+	}
+      for(j=i+1;j<5;j++) 
+	{
+	  factor=-a[j][i];
+	  for(k=0;k<5;k++)
+	    {
+	      a[j][k]+=a[i][k]*factor;b[j][k]+=b[i][k]*factor;
+	    }
+	}
+    } 
+  for(i=4;i>0;i--)
+    {
+      for(j=i-1;j>-1;j--)
+	{
+	  factor=-a[j][i];
+	  for(k=0;k<5;k++)
+	    {
+	      a[j][k]+=a[i][k]*factor;b[j][k]+=b[i][k]*factor;
+	    }
+	}
+    }
+  for(i=0;i<5;i++) for(j=0;j<5;j++) a[i][j]=b[i][j];
+}
+
+
+void TrigInDetTrackFitter::fit(TrigInDetTrackCollection* recoTracks )
+{
+	if(m_timers)
+	{
+		m_timer[0]->start();
+		m_timer[0]->pause();
+		m_timer[1]->start();
+		m_timer[1]->pause();
+		m_timer[2]->start();
+		m_timer[2]->pause();
+		m_timer[3]->start();
+		m_timer[3]->pause();
+		m_timer[4]->start();
+		m_timer[4]->pause();
+	}
+
+  for(auto trIt = recoTracks->begin(); trIt != recoTracks->end(); ++trIt) {
+		fitTrack(**trIt);
+	}
+
+	if(m_timers) 
+	{
+		m_timer[0]->stop();
+		m_timer[1]->stop();
+		m_timer[2]->stop();
+		m_timer[3]->stop();
+		m_timer[4]->stop();
+	}
+}
+
+TrackCollection* TrigInDetTrackFitter::fit(const TrackCollection& recoTracks, const Trk::ParticleHypothesis& matEffects)
+{
+	if(m_timers)
+	{
+		m_timer[0]->start();
+		m_timer[0]->pause();
+		m_timer[1]->start();
+		m_timer[1]->pause();
+		m_timer[2]->start();
+		m_timer[2]->pause();
+		m_timer[3]->start();
+		m_timer[3]->pause();
+		m_timer[4]->start();
+		m_timer[4]->pause();
+	}
+	TrackCollection* fittedTracks = new TrackCollection();	
+  for(auto trIt = recoTracks.begin(); trIt != recoTracks.end(); ++trIt) {
+		Trk::Track* fittedTrack = fitTrack(**trIt, matEffects);
+		if (fittedTrack!=nullptr) {
+			fittedTracks->push_back(fittedTrack);
+		}
+	}
+	if(m_timers) 
+	{
+		m_timer[0]->stop();
+		m_timer[1]->stop();
+		m_timer[2]->stop();
+		m_timer[3]->stop();
+		m_timer[4]->stop();
+	}
+	return fittedTracks;
+}
+
+void TrigInDetTrackFitter::fitTrack(TrigInDetTrack& recoTrack ) {
+
+	TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>(recoTrack.param());
+	if(param==NULL)
+	{
+		ATH_MSG_WARNING("Fit Failed -- TrigInDetTrack has no parameters");
+		return;
+	}
+
+	// 1. Create initial track state:
+	double Rk[5];
+	Rk[0]=param->a0();
+	Rk[1]=param->z0();
+	Rk[2]=param->phi0();
+	double Theta=2.0*atan(exp(-param->eta()));
+	Rk[3]=Theta;
+	Rk[4]=1000.0*sin(Theta)/param->pT();//MeV->GeV
+	double Pt=param->pT();
+
+	if(fabs(Pt)<100.0)
+	{
+		ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+		return;
+	}
+
+	// 2. Create filtering nodes
+
+	if(m_timers) m_timer[0]->resume();
+	std::vector<Trk::TrkBaseNode*> vpTrkNodes;
+	std::vector<Trk::TrkTrackState*> vpTrackStates;
+	bool trackResult = m_trackMaker->createDkfTrack(*(recoTrack.siSpacePoints()),vpTrkNodes, m_DChi2);
+	int nHits=vpTrkNodes.size();
+	if(m_timers) 
+	{
+		m_timer[0]->pause();
+		m_timer[1]->resume();
+	}
+	ATH_MSG_VERBOSE(nHits<<" filtering nodes created");
+
+	if(!trackResult) return;
+
+	// 3. Main algorithm: filter and smoother (Rauch-Tung-Striebel)
+
+	m_algorithmId=recoTrack.algorithmId();
+	(m_fitStats[m_algorithmId]).m_nTracksTotal++;
+	//Trk::TrkTrackState* pTS = new Trk::TrkTrackState(Rk);
+	Trk::TrkTrackState* pTS = new Trk::TrkTrackState(Rk);
+	double Gk[5][5] = {{100.0,     0, 0,    0,    0},
+			   {0,     100.0, 0,    0,    0},
+			   {0,         0, 0.01, 0,    0},
+			   {0,         0, 0,    0.01, 0},
+			   {0,         0, 0,    0,    0.1}};
+	pTS->m_setTrackCovariance(Gk);
+	if(m_doMultScatt)  
+		pTS->m_setScatteringMode(1);
+	if(m_doBremm)
+		pTS->m_setScatteringMode(2);
+	vpTrackStates.push_back(pTS);
+
+	ATH_MSG_VERBOSE("Initial chi2: "<<recoTrack.chi2()<<" track authorId: "<<recoTrack.algorithmId());
+	ATH_MSG_VERBOSE("Initial params: locT="<<Rk[0]<<" locL="<<Rk[1]<<" phi="<<Rk[2]
+			<<" theta="<<Rk[3]<<" Q="<<Rk[4]<<" pT="<<sin(Rk[3])/Rk[4]<<" GeV");
+
+	std::vector<Trk::TrkBaseNode*>::iterator pnIt(vpTrkNodes.begin()),
+		pnEnd(vpTrkNodes.end());
+
+	bool OK=true;
+
+	double chi2tot=0.0;
+	int ndoftot=-5;
+
+	Trk::TrkPlanarSurface* pSB=nullptr;
+	Trk::TrkPlanarSurface* pSE=nullptr;
+	for(;pnIt!=pnEnd;++pnIt)
+	{
+		pSE=(*pnIt)->m_getSurface();
+		Trk::TrkTrackState* pNS=m_extrapolate(pTS,pSB,pSE);
+
+		pSB=pSE;
+		if(pNS!=nullptr)
+		{
+			// pNS->m_report();
+			vpTrackStates.push_back(pNS);
+
+			(*pnIt)->m_validateMeasurement(pNS);
+			ATH_MSG_VERBOSE("dChi2="<<(*pnIt)->m_getChi2());
+			if((*pnIt)->m_isValidated())
+			{
+				chi2tot+=(*pnIt)->m_getChi2();
+				ndoftot+=(*pnIt)->m_getNdof();
+			}
+			(*pnIt)->m_updateTrackState(pNS);
+			pTS=pNS;
+			Pt=1000.0*sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+			if(fabs(Pt)<200.0)
+			{
+				ATH_MSG_VERBOSE("Estimated Pt is too low "<<Pt<<" - skipping fit");
+				(m_fitStats[m_algorithmId]).m_fitErrors[2]++;
+				OK=false;break;
+			}
+		}
+		else
+		{
+			(m_fitStats[m_algorithmId]).m_fitErrors[0]++;
+			OK=false;break;
+		}
+	}
+	if(m_timers) m_timer[1]->pause();
+	if(OK)
+	{
+		if(m_timers) m_timer[2]->resume();
+		std::vector<Trk::TrkTrackState*>::reverse_iterator ptsIt(vpTrackStates.rbegin()),
+			ptsEnd(vpTrackStates.rend());
+
+		for(;ptsIt!=ptsEnd;++ptsIt)
+		{
+			(*ptsIt)->m_runSmoother();
+		}
+		if(m_timers) 
+		{
+			m_timer[2]->pause();
+			m_timer[3]->resume();
+		}      
+
+		pTS=(*vpTrackStates.begin());
+		//correct GeV->MeV
+
+		correctScale(pTS);
+
+		double Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+		double Phi0 = pTS->m_getTrackState(2);
+		if(Phi0>M_PI) Phi0-=2*M_PI;
+		if(Phi0<-M_PI) Phi0+=2*M_PI;
+		double Eta = -log(sin(0.5*pTS->m_getTrackState(3))/cos(0.5*pTS->m_getTrackState(3)));
+		double Z0 = pTS->m_getTrackState(1);
+		double D0 = pTS->m_getTrackState(0);
+
+		double errD0 = sqrt(pTS->m_getTrackCovariance(0,0));
+		double errZ0 = sqrt(pTS->m_getTrackCovariance(1,1));
+		double errPhi0 = sqrt(pTS->m_getTrackCovariance(2,2));
+		double errEta = sqrt(pTS->m_getTrackCovariance(3,3))/fabs(sin(pTS->m_getTrackState(3)));
+		double b=cos(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+		double c=-Pt/pTS->m_getTrackState(4);
+		double a=-1.0/sin(pTS->m_getTrackState(3));
+		double errPt = sqrt(b*b*(pTS->m_getTrackCovariance(3,3))+c*c*(pTS->m_getTrackCovariance(4,4))+
+				2.0*b*c*(pTS->m_getTrackCovariance(3,4)));
+
+		std::vector<double>* pCov=new std::vector<double>;
+		double CV[5][5];
+		CV[0][0]=pTS->m_getTrackCovariance(0,0);
+		CV[0][1]=pTS->m_getTrackCovariance(0,2);
+		CV[0][2]=pTS->m_getTrackCovariance(0,1);
+		CV[0][3]=a*(pTS->m_getTrackCovariance(0,3));
+		CV[0][4]=b*(pTS->m_getTrackCovariance(0,3))+c*(pTS->m_getTrackCovariance(0,4));
+		CV[1][1]=pTS->m_getTrackCovariance(2,2);
+
+		CV[1][2]=pTS->m_getTrackCovariance(1,2);
+		CV[1][3]=a*(pTS->m_getTrackCovariance(2,3));
+		CV[1][4]=b*(pTS->m_getTrackCovariance(2,3))+c*(pTS->m_getTrackCovariance(2,4));
+		CV[2][2]=pTS->m_getTrackCovariance(1,1);
+		CV[2][3]=a*(pTS->m_getTrackCovariance(1,3));
+		CV[2][4]=b*(pTS->m_getTrackCovariance(1,3))+c*(pTS->m_getTrackCovariance(1,4));
+		CV[3][3]=a*a*(pTS->m_getTrackCovariance(3,3));
+		CV[3][4]=a*(b*(pTS->m_getTrackCovariance(3,3))+c*(pTS->m_getTrackCovariance(3,4)));
+		CV[4][4]=b*b*(pTS->m_getTrackCovariance(3,3))+2.0*b*c*(pTS->m_getTrackCovariance(3,4))+
+			c*c*(pTS->m_getTrackCovariance(4,4));
+
+		for(int i=0;i<5;i++) {
+			for(int j=i;j<5;j++) {
+				pCov->push_back(CV[i][j]);
+			}
+		}
+		const TrigInDetTrackFitPar* tidtfp = new TrigInDetTrackFitPar(D0,Phi0,Z0,Eta, Pt,
+				errD0,errPhi0,errZ0,
+				errEta,errPt,pCov);
+
+		if(m_timers) 
+		{
+			m_timer[3]->pause();
+			m_timer[4]->resume();
+		}
+
+		ATH_MSG_VERBOSE("Total chi2 ="<<chi2tot<<" NDOF="<<ndoftot);
+		ATH_MSG_VERBOSE("Fitted parameters: d0="<<D0<<" phi0="<<Phi0<<" z0="<<Z0	
+				<<" eta0="<<Eta<<" pt="<<Pt);
+
+		if((ndoftot<0) || (fabs(Pt)<100.0) || (std::isnan(Pt)))
+		{
+			ATH_MSG_DEBUG("Fit failed - possibly floating point problem");;
+			delete tidtfp;
+			recoTrack.chi2(1e8);
+		}
+		else
+		{
+			delete param;
+			if(ndoftot>1) chi2tot/=ndoftot;
+			recoTrack.param(tidtfp);
+			recoTrack.chi2(chi2tot);
+		}
+	}
+	else
+	{
+		ATH_MSG_DEBUG("Forward Kalman filter: extrapolation failure ");
+		recoTrack.chi2(1e8);
+	}
+
+	pnIt=vpTrkNodes.begin();pnEnd=vpTrkNodes.end();
+	for(;pnIt!=pnEnd;++pnIt) 
+	{
+		delete((*pnIt)->m_getSurface());
+		delete (*pnIt);
+	}
+	vpTrkNodes.clear();
+	for(std::vector<Trk::TrkTrackState*>::iterator ptsIt=vpTrackStates.begin();
+			ptsIt!=vpTrackStates.end();++ptsIt) delete (*ptsIt);
+	vpTrackStates.clear();
+
+	if(m_timers) 
+	{
+		m_timer[4]->pause();
+	}
+}
+
+Trk::Track* TrigInDetTrackFitter::fitTrack(const Trk::Track& recoTrack, const Trk::ParticleHypothesis& matEffects) {
+
+	const Trk::TrackParameters* trackPars = recoTrack.perigeeParameters();
+	if(trackPars==nullptr) {
+		ATH_MSG_WARNING("Fit Failed -- TrkTrack has no parameters");
+		return nullptr;
+	}
+
+	// 1. Create initial track state:
+	double Rk[5];
+	Rk[0] = trackPars->parameters()[Trk::d0]; 
+	Rk[1] = trackPars->parameters()[Trk::z0]; 
+	Rk[2] = trackPars->parameters()[Trk::phi0]; 
+	if(Rk[2]>M_PI) Rk[2]-=2*M_PI; 
+	if(Rk[2]<-M_PI) Rk[2]+=2*M_PI;
+	double trk_theta = trackPars->parameters()[Trk::theta];
+	Rk[3] = trk_theta;
+	double trk_qOverP = trackPars->parameters()[Trk::qOverP];
+	Rk[4] = 1000.0*trk_qOverP;//MeV->GeV
+	double trk_Pt = sin(trk_theta)/trk_qOverP;
+
+	if(fabs(trk_Pt)<100.0)
+	{
+		ATH_MSG_DEBUG("Estimated Pt is too low "<<trk_Pt<<" - skipping fit");
+		return nullptr;
+	}
+
+	// 2. Create filtering nodes
+
+	if(m_timers) m_timer[0]->resume();
+	std::vector<Trk::TrkBaseNode*> vpTrkNodes;
+	std::vector<Trk::TrkTrackState*> vpTrackStates;
+	bool trackResult = m_trackMaker->createDkfTrack(recoTrack,vpTrkNodes, m_DChi2);
+	int nHits=vpTrkNodes.size();
+	if(m_timers) 
+	{
+		m_timer[0]->pause();
+		m_timer[1]->resume();
+	}
+	ATH_MSG_VERBOSE(nHits<<" filtering nodes created");
+
+	if(!trackResult) return nullptr;
+
+	// 3. Main algorithm: filter and smoother (Rauch-Tung-Striebel)
+
+	(m_fitStats[m_algorithmId]).m_nTracksTotal++;
+	Trk::TrkTrackState* pTS = new Trk::TrkTrackState(Rk);
+	double Gk[5][5] = {{100.0,     0, 0,    0,    0},
+			   {0,     100.0, 0,    0,    0},
+			   {0,         0, 0.01, 0,    0},
+			   {0,         0, 0,    0.01, 0},
+			   {0,         0, 0,    0,   0.1}};
+	pTS->m_setTrackCovariance(Gk);
+	if(m_doMultScatt)  
+		pTS->m_setScatteringMode(1);
+	if(m_doBremm)
+		pTS->m_setScatteringMode(2);
+	vpTrackStates.push_back(pTS);
+
+	//ATH_MSG_DEBUG("Initial chi2: "<<recoTrack.chi2()<<" track authorId: "<<recoTrack.algorithmId());
+	ATH_MSG_VERBOSE("Initial params: locT="<<Rk[0]<<" locL="<<Rk[1]<<" phi="<<Rk[2]
+			<<" theta="<<Rk[3]<<" Q="<<Rk[4]<<" pT="<<sin(Rk[3])/Rk[4]<<" GeV");
+
+	bool OK=true;
+
+	double chi2tot=0.0;
+	int ndoftot=-5;
+
+	Trk::TrkPlanarSurface* pSB=nullptr;
+	Trk::TrkPlanarSurface* pSE=nullptr;
+	for(auto pnIt = vpTrkNodes.begin(); pnIt!=vpTrkNodes.end(); ++pnIt) {
+		pSE=(*pnIt)->m_getSurface();
+		Trk::TrkTrackState* pNS=m_extrapolate(pTS,pSB,pSE);
+
+		pSB=pSE;
+		if(pNS!=nullptr) {
+			vpTrackStates.push_back(pNS);
+
+			(*pnIt)->m_validateMeasurement(pNS);
+			ATH_MSG_VERBOSE("dChi2="<<(*pnIt)->m_getChi2());
+			if((*pnIt)->m_isValidated())
+			{
+				chi2tot+=(*pnIt)->m_getChi2();
+				ndoftot+=(*pnIt)->m_getNdof();
+			}
+			(*pnIt)->m_updateTrackState(pNS);
+			pTS=pNS;
+			double est_Pt = 1000.0*sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+			if(fabs(est_Pt)<200.0)
+			{
+				ATH_MSG_VERBOSE("Estimated Pt is too low "<<est_Pt<<" - skipping fit");
+				(m_fitStats[m_algorithmId]).m_fitErrors[2]++;
+				OK=false;break;
+			}
+		}
+		else
+		{
+			(m_fitStats[m_algorithmId]).m_fitErrors[0]++;
+			OK=false;break;
+		}
+	}
+	if(m_timers) m_timer[1]->pause();
+	Trk::Track* fittedTrack = nullptr;
+	if(OK)
+	{
+		if(m_timers) m_timer[2]->resume();
+		for(auto ptsIt = vpTrackStates.rbegin();ptsIt!=vpTrackStates.rend();++ptsIt)
+		{
+			(*ptsIt)->m_runSmoother();
+		}
+		if(m_timers) 
+		{
+			m_timer[2]->pause();
+			m_timer[3]->resume();
+		}      
+
+		pTS=(*vpTrackStates.begin());
+		//correct GeV->MeV
+
+		correctScale(pTS);
+		
+    double qOverP = pTS->m_getTrackState(4);
+		double pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+		double phi0 = pTS->m_getTrackState(2);
+		if(phi0>M_PI) phi0-=2*M_PI;
+		if(phi0<-M_PI) phi0+=2*M_PI;
+    double theta = pTS->m_getTrackState(3);
+		double eta = -log(tan(0.5*theta));
+		double z0 = pTS->m_getTrackState(1);
+		double d0 = pTS->m_getTrackState(0);
+
+		if((ndoftot<0) || (fabs(pt)<100.0) || (std::isnan(pt)))
+		{
+		  ATH_MSG_DEBUG("Fit failed - possibly floating point problem");
+		}
+		else
+		{
+
+      AmgSymMatrix(5)* cov = new AmgSymMatrix(5);
+      for(int i=0;i<5;i++) {
+        for(int j=i;j<5;j++)
+        {
+          cov->fillSymmetric(i, j, pTS->m_getTrackCovariance(i,j));
+        }
+      }
+      Trk::PerigeeSurface perigeeSurface;
+      Trk::Perigee* perigee = new Trk::Perigee(d0, z0, phi0, theta, qOverP, perigeeSurface, cov);
+
+      std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
+      typePattern.set(Trk::TrackStateOnSurface::Perigee);
+      DataVector<const Trk::TrackStateOnSurface>* pParVec = new DataVector<const Trk::TrackStateOnSurface>;
+      pParVec->reserve(recoTrack.trackStateOnSurfaces()->size());
+      pParVec->push_back(new Trk::TrackStateOnSurface(0, perigee,0,0, typePattern));
+
+      for (auto tSOS = recoTrack.trackStateOnSurfaces()->begin(); tSOS != recoTrack.trackStateOnSurfaces()->end(); ++tSOS) {
+        //Don't store perigee - new perigee created above
+        if ((*tSOS)->type(Trk::TrackStateOnSurface::Perigee) == false) {
+          pParVec->push_back((*tSOS)->clone());
+        }
+      }
+      if(m_timers)
+      {
+        m_timer[3]->pause();
+        m_timer[4]->resume();
+      }
+
+      ATH_MSG_VERBOSE("Total chi2 ="<<chi2tot<<" NDOF="<<ndoftot);
+      ATH_MSG_VERBOSE("Fitted parameters: d0="<<d0<<" phi0="<<phi0<<" z0="<<z0	
+          <<" eta0="<<eta<<" pt="<<pt);
+      Trk::FitQuality* pFQ=new Trk::FitQuality(chi2tot,ndoftot);
+      Trk::TrackInfo info(recoTrack.info());
+      info.setParticleHypothesis(matEffects);
+      fittedTrack = new Trk::Track(info, pParVec, pFQ);//fittedTrack now owns pParVec and pFQ
+    }
+	}
+	else
+	{
+		ATH_MSG_DEBUG("Forward Kalman filter: extrapolation failure ");
+	}
+
+	for(auto pnIt = vpTrkNodes.begin(); pnIt!=vpTrkNodes.end(); ++pnIt) {
+		delete((*pnIt)->m_getSurface());
+		delete (*pnIt);
+	}
+	vpTrkNodes.clear();
+	for(auto ptsIt = vpTrackStates.begin();ptsIt!=vpTrackStates.end();++ptsIt) {
+		delete (*ptsIt);
+	}
+	vpTrackStates.clear();
+
+	if(m_timers)
+	{
+		m_timer[4]->pause();
+	}
+	return fittedTrack;
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2FastExtrapolationTool.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2FastExtrapolationTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..18305c8f80b415cb9938274efaad902ba3ef2432
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2FastExtrapolationTool.cxx
@@ -0,0 +1,540 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigL2FastExtrapolationTool tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 01.09.2005 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+#include "StoreGate/StoreGateSvc.h" 
+#include "GaudiKernel/ToolFactory.h"
+#include "StoreGate/DataHandle.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+#include "MagFieldInterfaces/IMagFieldSvc.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+#include "TrigInDetTrackFitter/ITrigL2FastExtrapolationTool.h"
+#include "TrigInDetTrackFitter/TrigL2FastExtrapolationTool.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+TrigL2FastExtrapolationTool::TrigL2FastExtrapolationTool(const std::string& t, 
+					   const std::string& n,
+					   const IInterface*  p ): 
+  AthAlgTool(t,n,p),
+  m_MagFieldSvc("AtlasFieldSvc",this->name())
+{
+  declareInterface< ITrigL2FastExtrapolationTool >( this );
+}
+
+StatusCode TrigL2FastExtrapolationTool::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+  MsgStream athenaLog(msgSvc(), name());
+   
+  StoreGateSvc* detStore;
+  sc = service("DetectorStore", detStore);
+  if ( sc.isFailure() ) { 
+    ATH_MSG_FATAL("DetStore service not found");
+    return StatusCode::FAILURE; 
+  }
+
+	ATH_MSG_INFO("Using Athena magnetic field service");
+	sc = m_MagFieldSvc.retrieve();
+	if(sc.isFailure()) 
+	{
+		ATH_MSG_ERROR("Unable to retrieve Athena MagFieldService");
+		return StatusCode::FAILURE;
+	}
+  ATH_MSG_INFO("TrigL2FastExtrapolationTool initialized ");
+  return sc;
+}
+
+StatusCode TrigL2FastExtrapolationTool::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+
+void TrigL2FastExtrapolationTool::m_getMagneticField(double r[3],double* B)
+{
+  B[0]=0.0;B[1]=0.0;B[2]=0.0;
+	double field[3];
+	m_MagFieldSvc->getField(r,field);//field is returned in kT
+	for(int i=0;i<3;i++) B[i]=field[i]/Gaudi::Units::kilogauss;//convert to kG
+}
+
+Trk::TrkTrackState* TrigL2FastExtrapolationTool::extrapolate(Trk::TrkTrackState* pTS, 
+							     Trk::TrkPlanarSurface* pSB,
+							     Trk::TrkPlanarSurface* pSE,
+							     bool smooth)
+{
+  const double C=0.02999975;
+  const double minStep=30.0;
+	  
+  double sint,cost,sinf,cosf;
+  double gP[3],gPi[3],lP[3],gV[3],a,b,c,s,J0[7][5],Rf[5],descr,CQ,Ac,Av,Cc;
+  double V[3],P[3],M[3][3],AG[5][5],D[4],J[5][5],Jm[7][7],Gf[5][5],
+    J1[5][7],gB[3],gBi[3],gBf[3],dBds[3],Buf[5][7],DVx,DVy,DVz;
+  int i,j,m,nStep,nStepMax;
+  double sl,ds,path=0.0;
+
+
+  bool samePlane=false;
+
+  if(pSB!=NULL)
+    {   
+      double diff=0.0;
+      for(i=0;i<4;i++) diff+=fabs(pSE->m_getPar(i)-pSB->m_getPar(i));
+      if(diff<1e-5) {
+	samePlane=true;	
+	//(m_fitStats[m_algorithmId]).m_fitErrors[0]++;
+	//std::cout<<"Starting plane and target plane are the same !"<<std::endl;
+      }
+    }
+
+  if(!samePlane) {
+
+    //m_numericalJacobian(pTS,pSB,pSE,J);
+
+    sint=sin(pTS->m_getTrackState(3));cosf=cos(pTS->m_getTrackState(2));
+    sinf=sin(pTS->m_getTrackState(2));cost=cos(pTS->m_getTrackState(3));
+    gV[0]=sint*cosf;gV[1]=sint*sinf;gV[2]=cost;CQ=C*pTS->m_getTrackState(4);
+
+    memset(&J0[0][0],0,sizeof(J0));
+    
+    if(pSB!=NULL)
+      {
+	double L[3][3];
+	lP[0]=pTS->m_getTrackState(0);lP[1]=pTS->m_getTrackState(1);lP[2]=0.0;
+	pSB->m_transformPointToGlobal(lP,gP);
+	for(i=0;i<3;i++) for(j=0;j<3;j++) L[i][j]=pSB->m_getInvRotMatrix(i,j);
+	
+	J0[0][0]=L[0][0];J0[0][1]=L[0][1];
+	J0[1][0]=L[1][0];J0[1][1]=L[1][1];
+	J0[2][0]=L[2][0];J0[2][1]=L[2][1];
+	J0[3][2]=-sinf*sint;J0[3][3]=cosf*cost;
+	J0[4][2]= cosf*sint;J0[4][3]=sinf*cost;
+	J0[5][3]=-sint;
+	J0[6][4]=1.0;
+      }
+    else
+      {
+	gP[0]=-pTS->m_getTrackState(0)*sinf;
+	gP[1]= pTS->m_getTrackState(0)*cosf;
+	gP[2]= pTS->m_getTrackState(1);
+	J0[0][0]=-sinf;J0[0][2]=-pTS->m_getTrackState(0)*cosf;
+	J0[1][0]= cosf;J0[1][2]=-pTS->m_getTrackState(0)*sinf;
+	J0[2][1]=1.0;
+	J0[3][2]=-sinf*sint;J0[3][3]=cosf*cost;
+	J0[4][2]= cosf*sint;J0[4][3]=sinf*cost;
+	J0[5][3]=-sint;
+	J0[6][4]=1.0;
+      }
+    for(i=0;i<4;i++) D[i]=pSE->m_getPar(i);
+    for(i=0;i<3;i++) gPi[i]=gP[i];
+    
+    m_getMagneticField(gP,gB);
+    
+    for(i=0;i<3;i++) gBi[i]=gB[i];
+    
+    c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+    b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+    a=0.5*CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+	      gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+	      gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+    
+    descr=b*b-4.0*a*c;
+    
+    if(descr<0.0) 
+      {
+	//      printf("D<0 - extrapolation failed\n");
+	return NULL;
+      }
+    
+    bool useExpansion=true;
+    double ratio = 4*a*c/(b*b);
+    
+    if(fabs(ratio)>0.1) 
+      useExpansion = false;
+    
+    if(useExpansion) {
+      sl=-c/b;
+      sl=sl*(1-a*sl/b);
+    }
+    else {
+      int signb = (b<0.0)?-1:1;
+      sl = (-b+signb*sqrt(descr))/(2*a);
+    }
+    
+    if(fabs(sl)<minStep) nStepMax=1;
+    else
+      {
+	nStepMax=(int)(fabs(sl)/minStep)+1;
+      }
+    if((nStepMax<0)||(nStepMax>1000))
+      {
+	return NULL;
+      } 
+    Av=sl*CQ;
+    Ac=0.5*sl*Av;
+    DVx=gV[1]*gB[2]-gV[2]*gB[1];
+    DVy=gV[2]*gB[0]-gV[0]*gB[2];
+    DVz=gV[0]*gB[1]-gV[1]*gB[0];
+    
+    P[0]=gP[0]+gV[0]*sl+Ac*DVx;
+    P[1]=gP[1]+gV[1]*sl+Ac*DVy;
+    P[2]=gP[2]+gV[2]*sl+Ac*DVz;
+    V[0]=gV[0]+Av*DVx;
+    V[1]=gV[1]+Av*DVy;
+    V[2]=gV[2]+Av*DVz;
+  
+    m_getMagneticField(P,gB);
+    
+    for(i=0;i<3;i++) gBf[i]=gB[i];
+    for(i=0;i<3;i++)
+      {
+	dBds[i]=(gBf[i]-gBi[i])/sl;
+	gB[i]=gBi[i];
+      }
+    nStep=nStepMax;path=0.0;
+    while(nStep>0)
+      {
+	c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+	b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+	a=0.5*CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+		  gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+		  gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+	
+	ratio = 4*a*c/(b*b);
+	if(fabs(ratio)>0.1) 
+	  useExpansion = false;
+	else useExpansion = true;
+	
+	if(useExpansion) {
+	  sl=-c/b;
+	  sl=sl*(1-a*sl/b);
+	}
+	else {
+	  descr=b*b-4.0*a*c;
+	  if(descr<0.0) 
+	    {
+	      // printf("D<0 - extrapolation failed\n");
+	      return NULL;
+	    }
+	  int signb = (b<0.0)?-1:1;
+	  sl = (-b+signb*sqrt(descr))/(2*a);
+	}
+	
+	ds=sl/nStep;path+=ds;
+	Av=ds*CQ;
+	Ac=0.5*ds*Av;
+	DVx=gV[1]*gB[2]-gV[2]*gB[1];
+	DVy=gV[2]*gB[0]-gV[0]*gB[2];
+	DVz=gV[0]*gB[1]-gV[1]*gB[0];
+	
+	P[0]=gP[0]+gV[0]*ds+Ac*DVx;
+	P[1]=gP[1]+gV[1]*ds+Ac*DVy;
+	P[2]=gP[2]+gV[2]*ds+Ac*DVz;
+	V[0]=gV[0]+Av*DVx;
+	V[1]=gV[1]+Av*DVy;
+	V[2]=gV[2]+Av*DVz;
+	for(i=0;i<3;i++) 
+	  {
+	    gV[i]=V[i];gP[i]=P[i];
+	  }
+	for(i=0;i<3;i++) gB[i]+=dBds[i]*ds;
+	nStep--;
+      }
+    pSE->m_transformPointToLocal(gP,lP);
+    Rf[0]=lP[0];Rf[1]=lP[1];
+    Rf[2]=atan2(V[1],V[0]);
+
+    if(fabs(V[2])>1.0) return NULL;
+
+    Rf[3]=acos(V[2]);
+    Rf[4]=pTS->m_getTrackState(4);
+
+    gV[0]=sint*cosf;gV[1]=sint*sinf;gV[2]=cost;
+
+    for(i=0;i<4;i++) D[i]=pSE->m_getPar(i);
+    for(i=0;i<3;i++) gP[i]=gPi[i];
+    
+    for(i=0;i<3;i++)
+      {
+	gB[i]=0.5*(gBi[i]+gBf[i]);
+      }
+    
+    c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+    b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+    a=CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+	  gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+	  gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+    
+  ratio = 4*a*c/(b*b);
+  if(fabs(ratio)>0.1) 
+    useExpansion = false;
+  else useExpansion = true;
+
+  if(useExpansion) {
+    s=-c/b;
+    s=s*(1-a*sl/b);
+  }
+  else {
+    descr=b*b-4.0*a*c;
+    if(descr<0.0) 
+      {
+	// printf("D<0 - extrapolation failed\n");
+	return NULL;
+      }
+    int signb = (b<0.0)?-1:1;
+    s = (-b+signb*sqrt(descr))/(2*a);
+  }
+
+  Av=s*CQ;
+  Ac=0.5*s*Av;
+  Cc=0.5*s*s*C;
+
+  DVx=gV[1]*gB[2]-gV[2]*gB[1];
+  DVy=gV[2]*gB[0]-gV[0]*gB[2];
+  DVz=gV[0]*gB[1]-gV[1]*gB[0];
+
+  P[0]=gP[0]+gV[0]*s+Ac*DVx;
+  P[1]=gP[1]+gV[1]*s+Ac*DVy;
+  P[2]=gP[2]+gV[2]*s+Ac*DVz;
+
+  V[0]=gV[0]+Av*DVx;V[1]=gV[1]+Av*DVy;V[2]=gV[2]+Av*DVz;
+
+  pSE->m_transformPointToLocal(P,lP);
+  
+  memset(&Jm[0][0],0,sizeof(Jm));
+
+  for(i=0;i<3;i++) for(j=0;j<3;j++) M[i][j]=pSE->m_getRotMatrix(i,j);
+  
+  double coeff[3], dadVx,dadVy,dadVz,dadQ,dsdx,dsdy,dsdz,dsdVx,dsdVy,dsdVz,dsdQ;
+  coeff[0]=-c*c/(b*b*b);
+  coeff[1]=c*(1.0+3.0*c*a/(b*b))/(b*b);
+  coeff[2]=-(1.0+2.0*c*a/(b*b))/b;
+
+  dadVx=0.5*CQ*(-D[1]*gB[2]+D[2]*gB[1]);
+  dadVy=0.5*CQ*( D[0]*gB[2]-D[2]*gB[0]);
+  dadVz=0.5*CQ*(-D[0]*gB[1]+D[1]*gB[0]);
+  dadQ=0.5*C*(D[0]*DVx+D[1]*DVy+D[2]*DVz);
+  
+  dsdx=coeff[2]*D[0];
+  dsdy=coeff[2]*D[1];
+  dsdz=coeff[2]*D[2];
+  dsdVx=coeff[0]*dadVx+coeff[1]*D[0];
+  dsdVy=coeff[0]*dadVy+coeff[1]*D[1];
+  dsdVz=coeff[0]*dadVz+coeff[1]*D[2];
+  dsdQ=coeff[0]*dadQ;
+
+  Jm[0][0]=1.0+V[0]*dsdx;
+  Jm[0][1]=    V[0]*dsdy;
+  Jm[0][2]=    V[0]*dsdz;
+  
+  Jm[0][3]=  s+V[0]*dsdVx;
+  Jm[0][4]=    V[0]*dsdVy+Ac*gB[2];
+  Jm[0][5]=    V[0]*dsdVz-Ac*gB[1];
+  Jm[0][6]=    V[0]*dsdQ+Cc*DVx;
+
+  Jm[1][0]=    V[1]*dsdx;
+  Jm[1][1]=1.0+V[1]*dsdy;
+  Jm[1][2]=    V[1]*dsdz;
+
+  Jm[1][3]=    V[1]*dsdVx-Ac*gB[2];
+  Jm[1][4]=  s+V[1]*dsdVy;
+  Jm[1][5]=    V[1]*dsdVz+Ac*gB[0];
+  Jm[1][6]=    V[1]*dsdQ+Cc*DVy;
+  
+  Jm[2][0]=    V[2]*dsdx;
+  Jm[2][1]=    V[2]*dsdy;
+  Jm[2][2]=1.0+V[2]*dsdz;
+  Jm[2][3]=    V[2]*dsdVx+Ac*gB[1];
+  Jm[2][4]=    V[2]*dsdVy-Ac*gB[0];
+  Jm[2][5]=  s+V[2]*dsdVz;
+  Jm[2][6]=    V[2]*dsdQ+Cc*DVz;
+
+  Jm[3][0]=dsdx*CQ*DVx;
+  Jm[3][1]=dsdy*CQ*DVx;
+  Jm[3][2]=dsdz*CQ*DVx;
+  
+  Jm[3][3]=1.0+dsdVx*CQ*DVx;
+  Jm[3][4]=CQ*(dsdVy*DVx+s*gB[2]);
+  Jm[3][5]=CQ*(dsdVz*DVx-s*gB[1]);
+  
+  Jm[3][6]=(CQ*dsdQ+C*s)*DVx;
+  
+  Jm[4][0]=dsdx*CQ*DVy;
+  Jm[4][1]=dsdy*CQ*DVy;
+  Jm[4][2]=dsdz*CQ*DVy;
+
+  Jm[4][3]=CQ*(dsdVx*DVy-s*gB[2]);
+  Jm[4][4]=1.0+dsdVy*CQ*DVy;
+  Jm[4][5]=CQ*(dsdVz*DVy+s*gB[0]);
+  
+  Jm[4][6]=(CQ*dsdQ+C*s)*DVy;
+  
+  Jm[5][0]=dsdx*CQ*DVz;
+  Jm[5][1]=dsdy*CQ*DVz;
+  Jm[5][2]=dsdz*CQ*DVz;
+  Jm[5][3]=CQ*(dsdVx*DVz+s*gB[1]);
+  Jm[5][4]=CQ*(dsdVy*DVz-s*gB[0]);
+  Jm[5][5]=1.0+dsdVz*CQ*DVz;
+  Jm[5][6]=(CQ*dsdQ+C*s)*DVz;
+  
+  Jm[6][6]=1.0;
+  
+  memset(&J1[0][0],0,sizeof(J1));
+
+  J1[0][0]=M[0][0];J1[0][1]=M[0][1];J1[0][2]=M[0][2];
+  J1[1][0]=M[1][0];J1[1][1]=M[1][1];J1[1][2]=M[1][2];
+  J1[2][3]=-V[1]/(V[0]*V[0]+V[1]*V[1]);
+  J1[2][4]= V[0]/(V[0]*V[0]+V[1]*V[1]);
+  J1[3][5]=-1.0/sqrt(1-V[2]*V[2]);
+  J1[4][6]=1.0;
+
+  for(i=0;i<7;i++)
+    {
+      for(j=0;j<2;j++)
+	Buf[j][i]=J1[j][0]*Jm[0][i]+J1[j][1]*Jm[1][i]+J1[j][2]*Jm[2][i];
+      Buf[2][i]=J1[2][3]*Jm[3][i]+J1[2][4]*Jm[4][i];
+      Buf[3][i]=J1[3][5]*Jm[5][i];
+      Buf[4][i]=Jm[6][i];
+    }
+  
+   if(pSB!=NULL)
+     {
+       for(i=0;i<5;i++)
+	 {
+	   J[i][0]=Buf[i][0]*J0[0][0]+Buf[i][1]*J0[1][0]+Buf[i][2]*J0[2][0];
+	   J[i][1]=Buf[i][0]*J0[0][1]+Buf[i][1]*J0[1][1]+Buf[i][2]*J0[2][1];
+	   J[i][2]=Buf[i][3]*J0[3][2]+Buf[i][4]*J0[4][2];
+	   J[i][3]=Buf[i][3]*J0[3][3]+Buf[i][4]*J0[4][3]+Buf[i][5]*J0[5][3];
+	   J[i][4]=Buf[i][6];
+	 }
+     }
+   else
+     {      
+       for(i=0;i<5;i++)
+	 {
+	   J[i][0]=Buf[i][0]*J0[0][0]+Buf[i][1]*J0[1][0];
+	   J[i][1]=Buf[i][2];
+	   J[i][2]=Buf[i][0]*J0[0][2]+Buf[i][1]*J0[1][2]+Buf[i][3]*J0[3][2]+Buf[i][4]*J0[4][2];
+	   J[i][3]=Buf[i][3]*J0[3][3]+Buf[i][4]*J0[4][3]+Buf[i][5]*J0[5][3];
+	   J[i][4]=Buf[i][6];
+	 }
+     }
+  }
+  else {
+    Rf[0]=pTS->m_getTrackState(0);
+    Rf[1]=pTS->m_getTrackState(1);	
+    Rf[2]=pTS->m_getTrackState(2);
+    Rf[3]=pTS->m_getTrackState(3);
+    Rf[4]=pTS->m_getTrackState(4);
+    memset(&J[0][0],0,sizeof(J));
+    for(i=0;i<5;i++) J[i][i]=1.0;
+  }
+
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      AG[i][j]=0.0;for(m=0;m<5;m++) AG[i][j]+=J[i][m]*pTS->m_getTrackCovariance(m,j);
+    }
+  for(i=0;i<5;i++) for(j=i;j<5;j++)
+    {
+      Gf[i][j]=0.0;
+      for(m=0;m<5;m++) Gf[i][j]+=AG[i][m]*J[j][m];
+      Gf[j][i]=Gf[i][j];
+    }
+
+  Trk::TrkTrackState* pTE=new Trk::TrkTrackState(pTS);
+
+  pTE->m_setTrackState(Rf);
+  pTE->m_setTrackCovariance(Gf);
+  pTE->m_attachToSurface(pSE);
+  pTE->m_applyMaterialEffects();
+
+  if(smooth)
+    {
+      double A[5][5],Gi[5][5];
+      for(i=0;i<5;i++) for(j=0;j<5;j++)
+	{
+	  Gi[i][j]=pTE->m_getTrackCovariance(i,j);
+	}
+      m_matrixInversion5x5(Gi);
+      for(i=0;i<5;i++) for(j=0;j<5;j++)
+	{
+	  A[i][j]=0.0;
+	  for(m=0;m<5;m++) A[i][j]+=AG[m][i]*Gi[m][j];
+	}
+      pTE->m_setPreviousState(pTS);
+      pTE->m_setSmootherGain(A);
+    }
+
+  return pTE;
+}
+
+void TrigL2FastExtrapolationTool::m_matrixInversion5x5(double a[5][5])
+{
+  /**** 5x5 matrix inversion by Gaussian elimination ****/
+  int i,j,k,l;
+  double factor;
+  double temp[5];
+  double b[5][5];
+  // Set b to I
+
+  memset(&b[0][0],0,sizeof(b));
+  b[0][0]=1.0;b[1][1]=1.0;b[2][2]=1.0;b[3][3]=1.0;b[4][4]=1.0;
+  
+  for(i=0;i<5;i++)
+    {
+      for(j=i+1;j<5;j++)
+	if (fabs(a[i][i])<fabs(a[j][i]))
+	  {
+	    for(l=0;l<5;l++) temp[l]=a[i][l];
+	    for(l=0;l<5;l++) a[i][l]=a[j][l];
+	    for(l=0;l<5;l++) a[j][l]=temp[l];
+	    for(l=0;l<5;l++) temp[l]=b[i][l];
+	    for(l=0;l<5;l++) b[i][l]=b[j][l];
+	    for(l=0;l<5;l++) b[j][l]=temp[l];
+	  }
+      factor=a[i][i];
+      for(j=4;j>-1;j--) 
+	{
+	  b[i][j]/=factor;a[i][j]/=factor;
+	}
+      for(j=i+1;j<5;j++) 
+	{
+	  factor=-a[j][i];
+	  for(k=0;k<5;k++)
+	    {
+	      a[j][k]+=a[i][k]*factor;b[j][k]+=b[i][k]*factor;
+	    }
+	}
+    } 
+  for(i=4;i>0;i--)
+    {
+      for(j=i-1;j>-1;j--)
+	{
+	  factor=-a[j][i];
+	  for(k=0;k<5;k++)
+	    {
+	      a[j][k]+=a[i][k]*factor;b[j][k]+=b[i][k]*factor;
+	    }
+	}
+    }
+  for(i=0;i<5;i++) for(j=0;j<5;j++) a[i][j]=b[i][j];
+}
+
+
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2HighPtTrackFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2HighPtTrackFitter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..70ac59e2d49443430805779afef72a4f43dc4b62
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2HighPtTrackFitter.cxx
@@ -0,0 +1,171 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigL2HighPtTrackFitter tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 16.06.2010 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+
+#include "GaudiKernel/ToolFactory.h"
+
+#include "TrkSurfaces/Surface.h"
+#include "TrkSurfaces/PlaneSurface.h"
+#include "TrkParameters/TrackParameters.h"
+
+#include "TrkPrepRawData/PrepRawData.h"
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+
+#include "TrkRIO_OnTrack/RIO_OnTrack.h"
+
+#include "TrigInDetTrackFitter/TrigL2HighPtTrackFitter.h"
+
+TrigL2HighPtTrackFitter::TrigL2HighPtTrackFitter(const std::string& t, 
+						 const std::string& n,
+						 const IInterface*  p ): 
+  AthAlgTool(t,n,p),
+  m_recalibrate(false),
+  m_fastExtrapolator("TrigL2FastExtrapolationTool"),
+  m_ROTcreator("Trk::RIO_OnTrackCreator/InDetTrigBroadInDetRotCreator")
+{
+  declareInterface< ITrigL2TrackFittingTool >( this );  
+  declareProperty( "fastExtrapolator", m_fastExtrapolator, "TrigL2FastExtrapolationTool");
+  declareProperty( "useROTs",m_recalibrate = true);
+  declareProperty( "ROTcreator", m_ROTcreator, "Trk::RIO_OnTrackCreator/InDetTrigBroadInDetRotCreator");
+}
+
+StatusCode TrigL2HighPtTrackFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+  MsgStream athenaLog(msgSvc(), name());
+
+  if(m_recalibrate)
+    {
+      sc=m_ROTcreator.retrieve();
+      if(sc.isFailure())
+	{
+	  ATH_MSG_ERROR("Could not retrieve RIO_OnTrack creator tool "<<m_ROTcreator);
+	  return StatusCode::FAILURE;
+	}
+    }
+  sc=m_fastExtrapolator.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve extrapolation tool"<<m_fastExtrapolator);
+      return sc;
+    }
+  ATH_MSG_INFO("TrigL2HighPtTrackFitter initialized ");
+  return sc;
+}
+
+StatusCode TrigL2HighPtTrackFitter::finalize()
+{
+  StatusCode sc = AlgTool::finalize(); 
+  return sc;
+}
+
+void TrigL2HighPtTrackFitter::m_recalibrateFilteringNode(Trk::TrkBaseNode* pN, Trk::TrkTrackState* pTS)
+{
+  if(pTS->m_getSurface()==NULL) return;
+  AmgSymMatrix(5)* pM = new AmgSymMatrix(5);
+
+  for(int i=0;i<5;i++) 
+    for(int j=0;j<5;j++)
+      (*pM)(i,j)=pTS->m_getTrackCovariance(i,j);
+  
+  const Trk::PlaneSurface& pTrkSB = dynamic_cast<const Trk::PlaneSurface&>(pN->m_getPrepRawData()->detectorElement()->surface());
+  Trk::TrackParameters* pTP=new Trk::AtaPlane(pTS->m_getTrackState(0),pTS->m_getTrackState(1),
+					      pTS->m_getTrackState(2),pTS->m_getTrackState(3),
+					      pTS->m_getTrackState(4),pTrkSB,
+					      pM);
+  
+  const Trk::RIO_OnTrack* pRIO = m_ROTcreator->correct(*(pN->m_getPrepRawData()),*pTP);
+  pN->m_updateWithRIO(pRIO);
+  
+  delete pTP;
+  delete pRIO;
+}
+
+Trk::TrkTrackState* TrigL2HighPtTrackFitter::fit(Trk::TrkTrackState* pTS, std::vector<Trk::TrkBaseNode*>& vpTrkNodes,
+						 bool runSmoother)
+{
+  std::vector<Trk::TrkTrackState*> vpTrackStates;
+  
+  vpTrackStates.clear();
+  vpTrackStates.push_back(pTS);
+
+  std::vector<Trk::TrkBaseNode*>::iterator pnIt(vpTrkNodes.begin()),
+    pnEnd(vpTrkNodes.end());
+
+  bool OK=true;
+  Trk::TrkPlanarSurface *pSB=NULL,*pSE;
+
+  for(;pnIt!=pnEnd;++pnIt)
+    {
+      pSE=(*pnIt)->m_getSurface();
+      Trk::TrkTrackState* pNS=m_fastExtrapolator->extrapolate(pTS,pSB,pSE,runSmoother);	  
+      pSB=pSE;
+      if(pNS!=NULL)
+	{
+	  vpTrackStates.push_back(pNS);
+
+	  if(m_recalibrate)
+	    {
+	      m_recalibrateFilteringNode((*pnIt), pNS);
+	    }
+	  
+	  (*pnIt)->m_validateMeasurement(pNS);
+		ATH_MSG_DEBUG("dChi2="<<(*pnIt)->m_getChi2());
+	  (*pnIt)->m_updateTrackState(pNS);
+	  pTS=pNS;
+	  double Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	  if(fabs(Pt)<200.0)
+	    {
+				ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+	      OK=false;break;
+	    }
+	}
+      else
+	{
+	  OK=false;break;
+	}
+    }
+  if(OK)
+    {
+      if(runSmoother)
+	{
+	  std::vector<Trk::TrkTrackState*>::reverse_iterator ptsIt(vpTrackStates.rbegin()),
+	    ptsEnd(vpTrackStates.rend());
+	  for(;ptsIt!=ptsEnd;++ptsIt)
+	    {
+	      (*ptsIt)->m_runSmoother();
+	    }
+	  pTS=new Trk::TrkTrackState( (*vpTrackStates.begin()));
+	}
+      else
+	pTS=new Trk::TrkTrackState( (*vpTrackStates.rbegin()));
+    }
+  else
+    {
+      pTS=NULL;
+      ATH_MSG_DEBUG("High Pt track fitter: extrapolation failure ");
+    }
+  for(std::vector<Trk::TrkTrackState*>::iterator ptsIt=vpTrackStates.begin();
+      ptsIt!=vpTrackStates.end();++ptsIt) delete (*ptsIt);
+  vpTrackStates.clear();
+  return pTS;
+
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2LowPtTrackFitter.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2LowPtTrackFitter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..aa9592a07f5deff079472e78ceac167bc59d75a0
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2LowPtTrackFitter.cxx
@@ -0,0 +1,323 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigL2LowPtTrackFitter tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 17.06.2010 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+#include <string.h>
+
+#include "GaudiKernel/ToolFactory.h"
+
+#include "TrkSurfaces/Surface.h"
+#include "TrkSurfaces/PlaneSurface.h"
+#include "TrkParameters/TrackParameters.h"
+#include "TrkPrepRawData/PrepRawData.h"
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+
+#include "TrkRIO_OnTrack/RIO_OnTrack.h"
+
+#include "TrigInDetTrackFitter/TrigL2LowPtTrackFitter.h"
+
+TrigL2LowPtTrackFitter::TrigL2LowPtTrackFitter(const std::string& t, 
+						 const std::string& n,
+						 const IInterface*  p ): 
+  AthAlgTool(t,n,p),
+  m_recalibrate(false),
+  m_fastExtrapolator("TrigL2FastExtrapolationTool"),
+  m_ROTcreator("Trk::RIO_OnTrackCreator/InDetTrigBroadInDetRotCreator"),
+  m_extrapolator("Trk::Extrapolator/InDetTrigExtrapolator")
+{
+  declareInterface< ITrigL2TrackFittingTool >( this );  
+  declareProperty( "fastExtrapolator", m_fastExtrapolator, "TrigL2FastExtrapolationTool");
+  declareProperty( "useROTs",m_recalibrate = true);
+  declareProperty( "ROTcreator", m_ROTcreator, "Trk::RIO_OnTrackCreator/InDetTrigBroadInDetRotCreator");
+  declareProperty( "TrackExtrapolatorTool",m_extrapolator, "Trk::Extrapolator/InDetTrigExtrapolator");
+}
+
+StatusCode TrigL2LowPtTrackFitter::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  if(m_recalibrate)
+    {
+      sc=m_ROTcreator.retrieve();
+      if(sc.isFailure())
+	{
+	  ATH_MSG_ERROR("Could not retrieve RIO_OnTrack creator tool "<<m_ROTcreator);
+	  return StatusCode::FAILURE;
+	}
+    }
+  sc=m_fastExtrapolator.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve extrapolation tool"<<m_fastExtrapolator);
+      return sc;
+    }
+  sc=m_extrapolator.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve extrapolation tool"<<m_extrapolator);
+      return sc;
+    }
+
+  ATH_MSG_INFO("TrigL2LowPtTrackFitter initialized ");
+  return sc;
+}
+
+StatusCode TrigL2LowPtTrackFitter::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+void TrigL2LowPtTrackFitter::m_recalibrateFilteringNode(Trk::TrkBaseNode* pN, Trk::TrkTrackState* pTS)
+{
+  if(pTS->m_getSurface()==NULL) return;
+
+  AmgSymMatrix(5)* pM = new AmgSymMatrix(5);
+
+  for(int i=0;i<5;i++) 
+    for(int j=0;j<5;j++)
+      (*pM)(i,j)=pTS->m_getTrackCovariance(i,j);
+  
+  const Trk::PlaneSurface& pTrkSB = dynamic_cast<const Trk::PlaneSurface&>(pN->m_getPrepRawData()->detectorElement()->surface());
+  Trk::TrackParameters* pTP=new Trk::AtaPlane(pTS->m_getTrackState(0),pTS->m_getTrackState(1),
+					      pTS->m_getTrackState(2),pTS->m_getTrackState(3),
+					      pTS->m_getTrackState(4),pTrkSB,
+					      pM);
+
+  const Trk::RIO_OnTrack* pRIO = m_ROTcreator->correct(*(pN->m_getPrepRawData()),*pTP);
+  pN->m_updateWithRIO(pRIO);
+  
+  delete pTP;
+  delete pRIO;
+}
+
+Trk::TrkTrackState* TrigL2LowPtTrackFitter::m_extrapolateOffline(Trk::TrkTrackState* pTS, 
+								 Trk::TrkPlanarSurface* pSB,
+								 Trk::TrkPlanarSurface* pSE,
+								 int dir)
+{
+  //1. create starting parameters
+  Trk::TrackParameters* pTP=NULL;
+  Trk::TrkTrackState* pTE=NULL;
+
+  if(pSB==NULL)
+    {
+      // 1a. MeasuredPerigee
+
+      AmgSymMatrix(5)* pM = new AmgSymMatrix(5);
+      pM->setZero();
+
+      for(int i=0;i<5;i++) 
+	for(int j=0;j<5;j++)
+	  (*pM)(i,j)=pTS->m_getTrackCovariance(i,j);
+      const Trk::PerigeeSurface perSurf;
+      pTP=new Trk::Perigee(pTS->m_getTrackState(0),pTS->m_getTrackState(1),
+			   pTS->m_getTrackState(2),pTS->m_getTrackState(3),
+			   pTS->m_getTrackState(4),perSurf, pM);
+    }
+  else
+    {
+      const Trk::PlaneSurface* pTrkSB = dynamic_cast<const Trk::PlaneSurface*>(pSB->m_getTrkSurface());
+      AmgSymMatrix(5)* pM = new AmgSymMatrix(5);
+      pM->setZero();
+
+      for(int i=0;i<5;i++) 
+	for(int j=0;j<5;j++)
+	  (*pM)(i,j)=pTS->m_getTrackCovariance(i,j);
+
+      pTP=new Trk::AtaPlane(pTS->m_getTrackState(0),pTS->m_getTrackState(1),
+			    pTS->m_getTrackState(2),pTS->m_getTrackState(3),
+			    pTS->m_getTrackState(4),*pTrkSB,pM);
+    }
+
+  // 2. Extrapolation
+
+  const Trk::TrackParameters* predPar = NULL;
+  if(dir>0)
+    {
+      predPar = m_extrapolator->extrapolate(*pTP,*pSE->m_getTrkSurface(),
+					    Trk::alongMomentum,false,
+					    Trk::pion);
+    }
+  else
+    {
+      if(pSE!=NULL)
+	predPar = m_extrapolator->extrapolate(*pTP,*pSE->m_getTrkSurface(),
+					      Trk::oppositeMomentum,false,
+					      Trk::pion);
+      else
+	{
+	  Trk::PerigeeSurface perSurf;
+	  predPar = m_extrapolator->extrapolate(*pTP,perSurf,
+						Trk::oppositeMomentum,false,
+						Trk::pion);
+	}
+    }
+
+  if(predPar!=NULL)
+    {
+      if(pSE!=NULL)
+	{
+	  const Trk::AtaPlane* pTPE = dynamic_cast<const Trk::AtaPlane*>(predPar);
+	  if(pTPE!=NULL) {
+	    // 4. Create new TrackState
+	    double Re[5],Ge[5][5];
+	    Re[0]=pTPE->parameters()[Trk::locX];Re[1]=pTPE->parameters()[Trk::locY];
+	    Re[2]=pTPE->parameters()[Trk::phi];Re[3]=pTPE->parameters()[Trk::theta];
+	    Re[4]=pTPE->parameters()[Trk::qOverP];
+	    
+	    for(int i=0;i<5;i++) 
+	      for(int j=0;j<5;j++)
+		Ge[i][j]=(*pTPE->covariance())(i,j);
+	    
+	    pTE=new Trk::TrkTrackState(pTS);
+	    pTE->m_setTrackState(Re);
+	    pTE->m_setTrackCovariance(Ge);
+	    pTE->m_attachToSurface(pSE);
+	  }
+	  else pTE=NULL;
+	}
+      else
+	{
+	  const Trk::Perigee* pTPE = dynamic_cast<const Trk::Perigee*>(predPar);
+	  if(pTPE!=NULL) {
+	    // 4. Create new TrackState
+	    double Re[5],Ge[5][5];
+	    Re[0]=pTPE->parameters()[Trk::d0];Re[1]=pTPE->parameters()[Trk::z0];
+	    Re[2]=pTPE->parameters()[Trk::phi];Re[3]=pTPE->parameters()[Trk::theta];
+	    Re[4]=pTPE->parameters()[Trk::qOverP];
+	    
+	    for(int i=0;i<5;i++) 
+	      for(int j=0;j<5;j++)
+		Ge[i][j]=(*pTPE->covariance())(i,j);
+	    
+	    pTE=new Trk::TrkTrackState(pTS);
+	    pTE->m_setTrackState(Re);
+	    pTE->m_setTrackCovariance(Ge);
+	  }
+	  else pTE=NULL;
+	}
+      delete predPar;
+    }
+  delete pTP;
+  return pTE;
+}
+
+Trk::TrkTrackState* TrigL2LowPtTrackFitter::fit(Trk::TrkTrackState* pTS, std::vector<Trk::TrkBaseNode*>& vpTrkNodes,
+						bool runSmoother)
+{
+
+  bool OK=true;
+  Trk::TrkPlanarSurface *pSB=NULL;
+  
+  // 1. Forward filter
+
+  for(std::vector<Trk::TrkBaseNode*>::iterator pnIt=vpTrkNodes.begin();pnIt!=vpTrkNodes.end();++pnIt)
+    {
+      Trk::TrkPlanarSurface* pSE=(*pnIt)->m_getSurface();
+      Trk::TrkTrackState* pNS=m_fastExtrapolator->extrapolate(pTS,pSB,pSE,false);
+      pSB=pSE;
+      if(pNS!=NULL)
+	{
+	  // m_recalibrateFilteringNode((*pnIt),pNS);
+
+	  (*pnIt)->m_validateMeasurement(pNS);
+		ATH_MSG_DEBUG("dChi2="<<(*pnIt)->m_getChi2());
+	  (*pnIt)->m_updateTrackState(pNS);
+	  delete pTS;
+	  pTS=pNS;
+	  double Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	  if(fabs(Pt)<200.0)
+	    {
+				ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+	      delete pTS;
+	      OK=false;break;
+	    }
+	}
+      else
+	{
+	  delete pTS;OK=false;break;
+	}
+    }
+  if(!OK) return NULL;
+
+  if(!runSmoother) return pTS;
+
+  // 2. Backward filter
+  // reset covariance
+  double Gk[5][5];
+  memset(&Gk[0][0],0,sizeof(Gk));
+  Gk[0][0]=100.0;Gk[1][1]=100.0;Gk[2][2]=0.01;Gk[3][3]=0.01;Gk[4][4]=1e-6;
+  pTS->m_setTrackCovariance(Gk);
+
+  for(std::vector<Trk::TrkBaseNode*>::reverse_iterator pnrIt=vpTrkNodes.rbegin();pnrIt!=vpTrkNodes.rend();++pnrIt)
+    {
+      Trk::TrkPlanarSurface* pSE=(*pnrIt)->m_getSurface();
+      Trk::TrkTrackState* pNS=NULL;
+      if(pSE!=pSB)
+	{		  
+	  double C1,C2,dist=0.0;
+	  for(int i=0;i<3;i++)
+	    {
+	      C1=pSB->m_getCenter()[i];C2=pSE->m_getCenter()[i];
+	      dist+=(C2-C1)*(C2-C1);
+	    }
+	  dist=sqrt(dist);
+	  if(dist>100.0)
+	    pNS=m_extrapolateOffline(pTS,pSB,pSE,-1);
+	  else
+	    pNS=m_fastExtrapolator->extrapolate(pTS,pSB,pSE,false);
+	}
+      else 
+	pNS=new Trk::TrkTrackState(pTS);
+
+      pSB=pSE;
+      if(pNS!=NULL)
+	{
+	  if(m_recalibrate)
+	    {
+	      m_recalibrateFilteringNode((*pnrIt),pNS);
+	    }
+	  (*pnrIt)->m_validateMeasurement(pNS);
+    ATH_MSG_DEBUG("dChi2="<<(*pnrIt)->m_getChi2());
+	  (*pnrIt)->m_updateTrackState(pNS);
+	  delete pTS;
+	  pTS=pNS;
+	  double Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	  if(fabs(Pt)<200.0)
+	    {
+				ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+	      delete pTS;
+	      OK=false;break;
+	    }
+	}
+      else
+	{
+	  delete pTS;OK=false;break;
+	}
+    }
+  if(!OK) return NULL;
+
+  // 3. Extrapolating back to perigee
+  Trk::TrkTrackState* pNS=m_extrapolateOffline(pTS,pSB,NULL,-1);
+  delete pTS;pTS=pNS;
+
+  return pTS;
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2ResidualCalculator.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2ResidualCalculator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..063f55b56b2dfe47ec6a79119df9bf3d2d5a0a37
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/TrigL2ResidualCalculator.cxx
@@ -0,0 +1,844 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TrigL2ResidualCalculator tool
+// -------------------------------
+// ATLAS Collaboration
+//
+// 11.11.2009 Package created
+//
+// Author: Dmitry Emeliyanov, RAL
+// e-mail: D.Emeliyanov@rl.ac.uk
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <iostream>
+
+#include "StoreGate/StoreGateSvc.h" 
+#include "GaudiKernel/ToolFactory.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "StoreGate/DataHandle.h"
+
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "InDetIdentifier/SCT_ID.h"
+#include "InDetIdentifier/PixelID.h" 
+
+#include "TrigInDetEvent/TrigInDetTrack.h"
+
+//#include "TrkSurfaces/Surface.h"
+//#include "TrkSurfaces/TrapezoidBounds.h"
+//#include "TrkParameters/MeasuredPerigee.h"
+
+#include "TrkPrepRawData/PrepRawData.h"
+#include "TrkDistributedKalmanFilter/TrkBaseNode.h"
+#include "TrkDistributedKalmanFilter/TrkFilteringNodes.h"
+#include "TrkDistributedKalmanFilter/TrkTrackState.h"
+#include "TrkDistributedKalmanFilter/TrkPlanarSurface.h"
+#include "MagFieldInterfaces/IMagFieldSvc.h"
+
+//#include "TrigInDetToolInterfaces/ITrigL2ResidualCalculator.h"
+#include "TrigInDetToolInterfaces/TrigL2HitResidual.h"
+#include "TrigInDetTrackFitter/TrigL2ResidualCalculator.h"
+
+TrigL2ResidualCalculator::TrigL2ResidualCalculator(const std::string& t, 
+					   const std::string& n,
+					   const IInterface*  p ) : 
+  AthAlgTool(t,n,p),
+  m_MagFieldSvc("AtlasFieldSvc",this->name()),
+  m_trackMaker("TrigDkfTrackMakerTool")
+{
+  declareInterface< ITrigL2ResidualCalculator >( this );
+  
+  declareProperty( "AthenaFieldService", m_MagFieldSvc, "AtlasFieldSvc");
+  declareProperty( "doMultScattering", m_doMultScatt = true);
+  declareProperty( "doBremmCorrection", m_doBremm=false);  
+  declareProperty( "Chi2Cut", m_DChi2 = 1000.0);
+  declareProperty( "OfflineClusters", m_offlineClusters = true);
+}
+
+StatusCode TrigL2ResidualCalculator::initialize()
+{
+  StatusCode sc = AthAlgTool::initialize();
+
+  StoreGateSvc* detStore;
+  sc = service("DetectorStore", detStore);
+  if ( sc.isFailure() ) { 
+    ATH_MSG_FATAL("DetStore service not found"); 
+    return StatusCode::FAILURE; 
+  }
+
+  if (detStore->retrieve(m_idHelper, "AtlasID").isFailure()) {
+    ATH_MSG_FATAL("Could not get AtlasDetectorID helper AtlasID");
+    return StatusCode::FAILURE;
+  } 
+
+  if (detStore->retrieve(m_pixelId, "PixelID").isFailure()) { 
+    ATH_MSG_FATAL("Could not get Pixel ID helper");
+    return StatusCode::FAILURE;  
+  }
+  if (detStore->retrieve(m_sctId, "SCT_ID").isFailure()) {  
+    ATH_MSG_FATAL("Could not get SCT ID helper");;
+    return StatusCode::FAILURE;
+  }
+	ATH_MSG_INFO("Using Athena magnetic field service");;
+	sc = m_MagFieldSvc.retrieve();
+	if(sc.isFailure()) 
+	{
+		ATH_MSG_ERROR("Unable to retrieve Athena MagFieldService");
+		return StatusCode::FAILURE;
+	}
+  sc=m_trackMaker.retrieve();
+  if(sc.isFailure())
+    {
+      ATH_MSG_ERROR("Could not retrieve "<<m_trackMaker);
+      return sc;
+    }
+  ATH_MSG_INFO("TrigL2ResidualCalculator constructed ");
+  return sc;
+}
+
+StatusCode TrigL2ResidualCalculator::finalize()
+{
+  StatusCode sc = AthAlgTool::finalize(); 
+  return sc;
+}
+
+
+void TrigL2ResidualCalculator::m_getMagneticField(double r[3],double* B)
+{
+  B[0]=0.0;B[1]=0.0;B[2]=0.0;
+	double field[3];
+	m_MagFieldSvc->getField(r,field);//field is returned in kT
+	for(int i=0;i<3;i++) B[i]=field[i]/CLHEP::kilogauss;//convert to kG
+}
+
+Trk::TrkTrackState* TrigL2ResidualCalculator::m_extrapolate(Trk::TrkTrackState* pTS, 
+							Trk::TrkPlanarSurface* pSB,
+							Trk::TrkPlanarSurface* pSE)
+{
+  const double C=0.02999975;
+  const double minStep=30.0;
+	  
+  double sint,cost,sinf,cosf;
+  double gP[3],gPi[3],lP[3],gV[3],a,b,c,s,J0[7][5],Rf[5],descr,CQ,Ac,Av,Cc;
+  double V[3],P[3],M[3][3],AG[5][5],D[4],J[5][5],Jm[7][7],Gi[5][5],Gf[5][5],
+    J1[5][7],A[5][5],gB[3],gBi[3],gBf[3],dBds[3],Buf[5][7],DVx,DVy,DVz;
+  int i,j,m,nStep,nStepMax;
+  double sl,ds,path=0.0;
+
+  //m_numericalJacobian(pTS,pSB,pSE,J);
+
+  sint=sin(pTS->m_getTrackState(3));cosf=cos(pTS->m_getTrackState(2));
+  sinf=sin(pTS->m_getTrackState(2));cost=cos(pTS->m_getTrackState(3));
+  gV[0]=sint*cosf;gV[1]=sint*sinf;gV[2]=cost;CQ=C*pTS->m_getTrackState(4);
+
+  memset(&J0[0][0],0,sizeof(J0));
+
+  if(pSB!=NULL)
+    {
+      double L[3][3];
+      lP[0]=pTS->m_getTrackState(0);lP[1]=pTS->m_getTrackState(1);lP[2]=0.0;
+      pSB->m_transformPointToGlobal(lP,gP);
+      for(i=0;i<3;i++) for(j=0;j<3;j++) L[i][j]=pSB->m_getInvRotMatrix(i,j);
+
+      J0[0][0]=L[0][0];J0[0][1]=L[0][1];
+      J0[1][0]=L[1][0];J0[1][1]=L[1][1];
+      J0[2][0]=L[2][0];J0[2][1]=L[2][1];
+      J0[3][2]=-sinf*sint;J0[3][3]=cosf*cost;
+      J0[4][2]= cosf*sint;J0[4][3]=sinf*cost;
+      J0[5][3]=-sint;
+      J0[6][4]=1.0;
+    }
+  else
+    {
+      gP[0]=-pTS->m_getTrackState(0)*sinf;
+      gP[1]= pTS->m_getTrackState(0)*cosf;
+      gP[2]= pTS->m_getTrackState(1);
+      J0[0][0]=-sinf;J0[0][2]=-pTS->m_getTrackState(0)*cosf;
+      J0[1][0]= cosf;J0[1][2]=-pTS->m_getTrackState(0)*sinf;
+      J0[2][1]=1.0;
+      J0[3][2]=-sinf*sint;J0[3][3]=cosf*cost;
+      J0[4][2]= cosf*sint;J0[4][3]=sinf*cost;
+      J0[5][3]=-sint;
+      J0[6][4]=1.0;
+    }
+  for(i=0;i<4;i++) D[i]=pSE->m_getPar(i);
+  for(i=0;i<3;i++) gPi[i]=gP[i];
+  
+  m_getMagneticField(gP,gB);
+
+  for(i=0;i<3;i++) gBi[i]=gB[i];
+ 
+  c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+  b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+  a=0.5*CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+	    gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+	    gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+
+  descr=b*b-4.0*a*c;
+
+  if(descr<0.0) 
+    {
+      //      printf("D<0 - extrapolation failed\n");
+      return NULL;
+    }
+  sl=-c/b;
+  sl=sl*(1-a*sl/b);
+
+  if(fabs(sl)<minStep) nStepMax=1;
+  else
+    {
+      nStepMax=(int)(fabs(sl)/minStep)+1;
+    }
+  if((nStepMax<0)||(nStepMax>1000))
+    {
+      return NULL;
+    } 
+  Av=sl*CQ;
+  Ac=0.5*sl*Av;
+  DVx=gV[1]*gB[2]-gV[2]*gB[1];
+  DVy=gV[2]*gB[0]-gV[0]*gB[2];
+  DVz=gV[0]*gB[1]-gV[1]*gB[0];
+  
+  P[0]=gP[0]+gV[0]*sl+Ac*DVx;
+  P[1]=gP[1]+gV[1]*sl+Ac*DVy;
+  P[2]=gP[2]+gV[2]*sl+Ac*DVz;
+  V[0]=gV[0]+Av*DVx;
+  V[1]=gV[1]+Av*DVy;
+  V[2]=gV[2]+Av*DVz;
+  
+  m_getMagneticField(P,gB);
+  
+  for(i=0;i<3;i++) gBf[i]=gB[i];
+  for(i=0;i<3;i++)
+    {
+      dBds[i]=(gBf[i]-gBi[i])/sl;
+      gB[i]=gBi[i];
+    }
+  nStep=nStepMax;path=0.0;
+  while(nStep>0)
+    {
+      c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+      b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+      a=0.5*CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+		gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+		gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+      sl=-c/b;
+      sl=sl*(1-a*sl/b);
+      ds=sl/nStep;path+=ds;
+      Av=ds*CQ;
+      Ac=0.5*ds*Av;
+      DVx=gV[1]*gB[2]-gV[2]*gB[1];
+      DVy=gV[2]*gB[0]-gV[0]*gB[2];
+      DVz=gV[0]*gB[1]-gV[1]*gB[0];
+
+      P[0]=gP[0]+gV[0]*ds+Ac*DVx;
+      P[1]=gP[1]+gV[1]*ds+Ac*DVy;
+      P[2]=gP[2]+gV[2]*ds+Ac*DVz;
+      V[0]=gV[0]+Av*DVx;
+      V[1]=gV[1]+Av*DVy;
+      V[2]=gV[2]+Av*DVz;
+      for(i=0;i<3;i++) 
+	{
+	  gV[i]=V[i];gP[i]=P[i];
+	}
+      for(i=0;i<3;i++) gB[i]+=dBds[i]*ds;
+      nStep--;
+    }
+  pSE->m_transformPointToLocal(gP,lP);
+  Rf[0]=lP[0];Rf[1]=lP[1];
+  Rf[2]=atan2(V[1],V[0]);
+
+  if(fabs(V[2])>1.0) return NULL;
+
+  Rf[3]=acos(V[2]);
+  Rf[4]=pTS->m_getTrackState(4);
+
+  gV[0]=sint*cosf;gV[1]=sint*sinf;gV[2]=cost;
+
+  for(i=0;i<4;i++) D[i]=pSE->m_getPar(i);
+  for(i=0;i<3;i++) gP[i]=gPi[i];
+
+  for(i=0;i<3;i++)
+    {
+      gB[i]=0.5*(gBi[i]+gBf[i]);
+    }
+
+  c=D[0]*gP[0]+D[1]*gP[1]+D[2]*gP[2]+D[3];
+  b=D[0]*gV[0]+D[1]*gV[1]+D[2]*gV[2];
+  a=CQ*(gB[0]*(D[1]*gV[2]-D[2]*gV[1])+
+	gB[1]*(D[2]*gV[0]-D[0]*gV[2])+
+	gB[2]*(D[0]*gV[1]-D[1]*gV[0]));
+  s=-c/b;
+  s=s*(1-a*s/b);
+  Av=s*CQ;
+  Ac=0.5*s*Av;
+  Cc=0.5*s*s*C;
+
+  DVx=gV[1]*gB[2]-gV[2]*gB[1];
+  DVy=gV[2]*gB[0]-gV[0]*gB[2];
+  DVz=gV[0]*gB[1]-gV[1]*gB[0];
+
+  P[0]=gP[0]+gV[0]*s+Ac*DVx;
+  P[1]=gP[1]+gV[1]*s+Ac*DVy;
+  P[2]=gP[2]+gV[2]*s+Ac*DVz;
+
+  V[0]=gV[0]+Av*DVx;V[1]=gV[1]+Av*DVy;V[2]=gV[2]+Av*DVz;
+
+  pSE->m_transformPointToLocal(P,lP);
+  
+  memset(&Jm[0][0],0,sizeof(Jm));
+
+  for(i=0;i<3;i++) for(j=0;j<3;j++) M[i][j]=pSE->m_getRotMatrix(i,j);
+  
+  double coeff[3], dadVx,dadVy,dadVz,dadQ,dsdx,dsdy,dsdz,dsdVx,dsdVy,dsdVz,dsdQ;
+  coeff[0]=-c*c/(b*b*b);
+  coeff[1]=c*(1.0+3.0*c*a/(b*b))/(b*b);
+  coeff[2]=-(1.0+2.0*c*a/(b*b))/b;
+
+  dadVx=0.5*CQ*(-D[1]*gB[2]+D[2]*gB[1]);
+  dadVy=0.5*CQ*( D[0]*gB[2]-D[2]*gB[0]);
+  dadVz=0.5*CQ*(-D[0]*gB[1]+D[1]*gB[0]);
+  dadQ=0.5*C*(D[0]*DVx+D[1]*DVy+D[2]*DVz);
+  
+  dsdx=coeff[2]*D[0];
+  dsdy=coeff[2]*D[1];
+  dsdz=coeff[2]*D[2];
+  dsdVx=coeff[0]*dadVx+coeff[1]*D[0];
+  dsdVy=coeff[0]*dadVy+coeff[1]*D[1];
+  dsdVz=coeff[0]*dadVz+coeff[1]*D[2];
+  dsdQ=coeff[0]*dadQ;
+
+  Jm[0][0]=1.0+V[0]*dsdx;
+  Jm[0][1]=    V[0]*dsdy;
+  Jm[0][2]=    V[0]*dsdz;
+  
+  Jm[0][3]=  s+V[0]*dsdVx;
+  Jm[0][4]=    V[0]*dsdVy+Ac*gB[2];
+  Jm[0][5]=    V[0]*dsdVz-Ac*gB[1];
+  Jm[0][6]=    V[0]*dsdQ+Cc*DVx;
+
+  Jm[1][0]=    V[1]*dsdx;
+  Jm[1][1]=1.0+V[1]*dsdy;
+  Jm[1][2]=    V[1]*dsdz;
+
+  Jm[1][3]=    V[1]*dsdVx-Ac*gB[2];
+  Jm[1][4]=  s+V[1]*dsdVy;
+  Jm[1][5]=    V[1]*dsdVz+Ac*gB[0];
+  Jm[1][6]=    V[1]*dsdQ+Cc*DVy;
+  
+  Jm[2][0]=    V[2]*dsdx;
+  Jm[2][1]=    V[2]*dsdy;
+  Jm[2][2]=1.0+V[2]*dsdz;
+  Jm[2][3]=    V[2]*dsdVx+Ac*gB[1];
+  Jm[2][4]=    V[2]*dsdVy-Ac*gB[0];
+  Jm[2][5]=  s+V[2]*dsdVz;
+  Jm[2][6]=    V[2]*dsdQ+Cc*DVz;
+
+  Jm[3][0]=dsdx*CQ*DVx;
+  Jm[3][1]=dsdy*CQ*DVx;
+  Jm[3][2]=dsdz*CQ*DVx;
+  
+  Jm[3][3]=1.0+dsdVx*CQ*DVx;
+  Jm[3][4]=CQ*(dsdVy*DVx+s*gB[2]);
+  Jm[3][5]=CQ*(dsdVz*DVx-s*gB[1]);
+  
+  Jm[3][6]=(CQ*dsdQ+C*s)*DVx;
+  
+  Jm[4][0]=dsdx*CQ*DVy;
+  Jm[4][1]=dsdy*CQ*DVy;
+  Jm[4][2]=dsdz*CQ*DVy;
+
+  Jm[4][3]=CQ*(dsdVx*DVy-s*gB[2]);
+  Jm[4][4]=1.0+dsdVy*CQ*DVy;
+  Jm[4][5]=CQ*(dsdVz*DVy+s*gB[0]);
+  
+  Jm[4][6]=(CQ*dsdQ+C*s)*DVy;
+  
+  Jm[5][0]=dsdx*CQ*DVz;
+  Jm[5][1]=dsdy*CQ*DVz;
+  Jm[5][2]=dsdz*CQ*DVz;
+  Jm[5][3]=CQ*(dsdVx*DVz+s*gB[1]);
+  Jm[5][4]=CQ*(dsdVy*DVz-s*gB[0]);
+  Jm[5][5]=1.0+dsdVz*CQ*DVz;
+  Jm[5][6]=(CQ*dsdQ+C*s)*DVz;
+  
+  Jm[6][6]=1.0;
+  
+  memset(&J1[0][0],0,sizeof(J1));
+
+  J1[0][0]=M[0][0];J1[0][1]=M[0][1];J1[0][2]=M[0][2];
+  J1[1][0]=M[1][0];J1[1][1]=M[1][1];J1[1][2]=M[1][2];
+  J1[2][3]=-V[1]/(V[0]*V[0]+V[1]*V[1]);
+  J1[2][4]= V[0]/(V[0]*V[0]+V[1]*V[1]);
+  J1[3][5]=-1.0/sqrt(1-V[2]*V[2]);
+  J1[4][6]=1.0;
+
+  for(i=0;i<7;i++)
+    {
+      for(j=0;j<2;j++)
+	Buf[j][i]=J1[j][0]*Jm[0][i]+J1[j][1]*Jm[1][i]+J1[j][2]*Jm[2][i];
+      Buf[2][i]=J1[2][3]*Jm[3][i]+J1[2][4]*Jm[4][i];
+      Buf[3][i]=J1[3][5]*Jm[5][i];
+      Buf[4][i]=Jm[6][i];
+    }
+  
+   if(pSB!=NULL)
+     {
+       for(i=0;i<5;i++)
+	 {
+	   J[i][0]=Buf[i][0]*J0[0][0]+Buf[i][1]*J0[1][0]+Buf[i][2]*J0[2][0];
+	   J[i][1]=Buf[i][0]*J0[0][1]+Buf[i][1]*J0[1][1]+Buf[i][2]*J0[2][1];
+	   J[i][2]=Buf[i][3]*J0[3][2]+Buf[i][4]*J0[4][2];
+	   J[i][3]=Buf[i][3]*J0[3][3]+Buf[i][4]*J0[4][3]+Buf[i][5]*J0[5][3];
+	   J[i][4]=Buf[i][6];
+	 }
+     }
+   else
+     {      
+       for(i=0;i<5;i++)
+	 {
+	   J[i][0]=Buf[i][0]*J0[0][0]+Buf[i][1]*J0[1][0];
+	   J[i][1]=Buf[i][2];
+	   J[i][2]=Buf[i][0]*J0[0][2]+Buf[i][1]*J0[1][2]+Buf[i][3]*J0[3][2]+Buf[i][4]*J0[4][2];
+	   J[i][3]=Buf[i][3]*J0[3][3]+Buf[i][4]*J0[4][3]+Buf[i][5]*J0[5][3];
+	   J[i][4]=Buf[i][6];
+	 }
+     }
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      AG[i][j]=0.0;for(m=0;m<5;m++) AG[i][j]+=J[i][m]*pTS->m_getTrackCovariance(m,j);
+    }
+  for(i=0;i<5;i++) for(j=i;j<5;j++)
+    {
+      Gf[i][j]=0.0;
+      for(m=0;m<5;m++) Gf[i][j]+=AG[i][m]*J[j][m];
+      Gf[j][i]=Gf[i][j];
+    }
+  Trk::TrkTrackState* pTE=new Trk::TrkTrackState(pTS);
+  pTE->m_setTrackState(Rf);
+  pTE->m_setTrackCovariance(Gf);
+  pTE->m_attachToSurface(pSE);
+  pTE->m_applyMaterialEffects();
+
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      Gi[i][j]=pTE->m_getTrackCovariance(i,j);
+    }
+
+  m_matrixInversion5x5(Gi);
+ 
+  for(i=0;i<5;i++) for(j=0;j<5;j++)
+    {
+      A[i][j]=0.0;
+      for(m=0;m<5;m++) A[i][j]+=AG[m][i]*Gi[m][j];
+    }
+  pTE->m_setPreviousState(pTS);
+  pTE->m_setSmootherGain(A);
+
+  return pTE;
+}
+
+void TrigL2ResidualCalculator::m_matrixInversion5x5(double a[5][5])
+{
+  /**** 5x5 matrix inversion by Gaussian elimination ****/
+
+  int i,j,k,l;
+  double factor;
+  double temp[5];
+  double b[5][5];
+  // Set b to I
+
+  memset(&b[0][0],0,sizeof(b));
+  b[0][0]=1.0;b[1][1]=1.0;b[2][2]=1.0;b[3][3]=1.0;b[4][4]=1.0;
+  
+  for(i=0;i<5;i++)
+    {
+      for(j=i+1;j<5;j++)
+	if (fabs(a[i][i])<fabs(a[j][i]))
+	  {
+	    for(l=0;l<5;l++) temp[l]=a[i][l];
+	    for(l=0;l<5;l++) a[i][l]=a[j][l];
+	    for(l=0;l<5;l++) a[j][l]=temp[l];
+	    for(l=0;l<5;l++) temp[l]=b[i][l];
+	    for(l=0;l<5;l++) b[i][l]=b[j][l];
+	    for(l=0;l<5;l++) b[j][l]=temp[l];
+	  }
+      factor=a[i][i];
+      for(j=4;j>-1;j--) 
+	{
+	  b[i][j]/=factor;a[i][j]/=factor;
+	}
+      for(j=i+1;j<5;j++) 
+	{
+	  factor=-a[j][i];
+	  for(k=0;k<5;k++)
+	    {
+	      a[j][k]+=a[i][k]*factor;b[j][k]+=b[i][k]*factor;
+	    }
+	}
+    } 
+  for(i=4;i>0;i--)
+    {
+      for(j=i-1;j>-1;j--)
+	{
+	  factor=-a[j][i];
+	  for(k=0;k<5;k++)
+	    {
+	      a[j][k]+=a[i][k]*factor;b[j][k]+=b[i][k]*factor;
+	    }
+	}
+    }
+  for(i=0;i<5;i++) for(j=0;j<5;j++) a[i][j]=b[i][j];
+}
+
+
+StatusCode TrigL2ResidualCalculator::getResiduals(const TrigInDetTrack* pT, std::vector<TrigL2HitResidual>& vResid)
+{
+ 
+  double Rk[5],Pt,Theta;
+
+  std::vector<Trk::TrkBaseNode*> vpTrkNodes;
+  std::vector<Trk::TrkTrackState*> vpTrackStates;
+
+  vResid.clear();
+
+  TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>(pT->param());
+  if(param==NULL)
+    {
+			ATH_MSG_WARNING("TrigL2ResidualCalculator failed -- TrigInDetTrack has no parameters"); 
+      return StatusCode::FAILURE;
+    }
+
+  // 1. Create initial track state:
+  
+  Rk[0]=param->a0();
+  Rk[1]=param->z0();
+  Rk[2]=param->phi0();
+  Theta=2.0*atan(exp(-param->eta()));
+  Rk[3]=Theta;
+  Rk[4]=sin(Theta)/param->pT();
+  Pt=param->pT();
+
+  if(fabs(Pt)<100.0)
+    {
+			ATH_MSG_DEBUG("TrigL2ResidualCalculator failed -- Estimated Pt is too low "<<Pt);
+      return StatusCode::FAILURE;
+    }
+
+  // 2. Create filtering nodes
+  
+  bool trackResult = m_trackMaker->createDkfTrack(*(pT->siSpacePoints()),vpTrkNodes, m_DChi2);
+  if(!trackResult) 
+    {
+			ATH_MSG_DEBUG("TrigDkfTrackMaker failed");
+      return StatusCode::FAILURE;
+    }
+
+  // 3. Main algorithm: filter and smoother (Rauch-Tung-Striebel)
+      
+  Trk::TrkTrackState* pTS = new Trk::TrkTrackState(Rk);
+  double Gk[5][5];
+  memset(&Gk[0][0],0,sizeof(Gk));
+  Gk[0][0]=100.0;Gk[1][1]=100.0;Gk[2][2]=0.01;Gk[3][3]=0.01;Gk[4][4]=1e-6;
+  pTS->m_setTrackCovariance(Gk);
+  if(m_doMultScatt)  
+    pTS->m_setScatteringMode(1);
+  if(m_doBremm)
+    pTS->m_setScatteringMode(2);
+  vpTrackStates.push_back(pTS);
+
+	ATH_MSG_DEBUG("Initial params: locT="<<Rk[0]<<" locL="<<Rk[1]<<" phi="<<Rk[2]
+			<<" theta="<<Rk[3]<<" Q="<<Rk[4]<<" pT="<<sin(Rk[3])/Rk[4]);
+  
+  std::vector<Trk::TrkBaseNode*>::iterator pnIt(vpTrkNodes.begin()),
+    pnEnd(vpTrkNodes.end());
+
+  bool OK=true;
+  Trk::TrkPlanarSurface *pSB=NULL,*pSE;
+  
+  for(;pnIt!=pnEnd;++pnIt)
+    {
+      pSE=(*pnIt)->m_getSurface();
+      Trk::TrkTrackState* pNS=m_extrapolate(pTS,pSB,pSE);
+      
+      pSB=pSE;
+      if(pNS!=NULL)
+	{
+	  vpTrackStates.push_back(pNS);
+	  
+	  (*pnIt)->m_validateMeasurement(pNS);
+    ATH_MSG_DEBUG("dChi2="<<(*pnIt)->m_getChi2());
+	  (*pnIt)->m_updateTrackState(pNS);
+	  pTS=pNS;
+	  Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	  if(fabs(Pt)<200.0)
+	    {
+				ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+	      OK=false;break;
+	    }
+	}
+      else
+	{
+	  OK=false;break;
+	}
+    }
+  if(OK)
+    {
+      std::vector<Trk::TrkTrackState*>::reverse_iterator ptsrIt(vpTrackStates.rbegin()),
+	ptsrEnd(vpTrackStates.rend());
+
+      for(;ptsrIt!=ptsrEnd;++ptsrIt)
+	{
+	  (*ptsrIt)->m_runSmoother();
+	}
+
+      std::vector<Trk::TrkBaseNode*>::iterator pnIt(vpTrkNodes.begin()),
+	pnEnd(vpTrkNodes.end());
+      std::vector<Trk::TrkTrackState*>::iterator ptsIt(vpTrackStates.begin());
+
+      for(;pnIt!=pnEnd;++pnIt)
+	{
+	  ++ptsIt;
+
+	  Trk::TrkTrackState* pNS=(*ptsIt);
+
+	  (*pnIt)->m_validateMeasurement(pNS);
+
+	  double r[2],V[2][2];
+
+	  int nSize=(*pnIt)->m_getResiduals(r);
+	  nSize=(*pnIt)->m_getInverseResidualVariance(V);
+	  const Trk::PrepRawData* pPRD = (*pnIt)->m_getPrepRawData();
+
+	  Identifier id = pPRD->identify();
+
+	  int Region=-1;
+	  if(m_idHelper->is_pixel(id))
+	    {
+	      Region=(m_pixelId->is_barrel(id))?1:2;
+	    }
+	  if(m_idHelper->is_sct(id))
+	    {
+	      Region=(m_sctId->is_barrel(id))?3:4;
+	    }
+	  if(nSize==1) {
+	    if(V[0][0]>0.0) {
+	      vResid.push_back(TrigL2HitResidual(id,Region,r[0],r[0]*sqrt(V[0][0])));
+	    }
+	    else {
+	      OK=false;
+	      break;
+	    }
+	  }
+	  else {
+	    if((V[0][0]>0.0) && (V[1][1]>0.0)) {
+	      vResid.push_back(TrigL2HitResidual(id,Region,r[0],r[0]*sqrt(V[0][0]),
+						 r[1],r[1]*sqrt(V[1][1])));
+	    }
+	    else {
+	      OK=false;
+	      break;
+	    }
+	  }
+	}
+    }
+  else
+    {
+      ATH_MSG_DEBUG("Forward Kalman filter: extrapolation failure ");
+    }
+  pnIt=vpTrkNodes.begin();pnEnd=vpTrkNodes.end();
+  for(;pnIt!=pnEnd;++pnIt) 
+    {
+      delete((*pnIt)->m_getSurface());
+      delete (*pnIt);
+    }
+  vpTrkNodes.clear();
+  for(std::vector<Trk::TrkTrackState*>::iterator ptsIt=vpTrackStates.begin();
+      ptsIt!=vpTrackStates.end();++ptsIt) delete (*ptsIt);
+  vpTrackStates.clear();
+  if(OK) return StatusCode::SUCCESS;
+  else return StatusCode::FAILURE;
+
+}
+
+StatusCode TrigL2ResidualCalculator::getUnbiassedResiduals(const TrigInDetTrack* pT, 
+							   std::vector<TrigL2HitResidual>& vResid)
+{
+ 
+  double Rk[5],Pt,Theta;
+
+  std::vector<Trk::TrkBaseNode*> vpTrkNodes;
+  std::vector<Trk::TrkTrackState*> vpTrackStates;
+
+  vResid.clear();
+
+  TrigInDetTrackFitPar* param=const_cast<TrigInDetTrackFitPar*>(pT->param());
+  if(param==NULL)
+    {
+			ATH_MSG_WARNING("TrigL2ResidualCalculator failed -- TrigInDetTrack has no parameters"); 
+      return StatusCode::FAILURE;
+    }
+
+  Pt=param->pT();
+  if(fabs(Pt)<100.0)
+    {
+			ATH_MSG_DEBUG("TrigL2ResidualCalculator failed -- Estimated Pt is too low "<<Pt);
+      return StatusCode::FAILURE;
+    }
+
+  // 1. Create filtering nodes
+  
+  bool trackResult = m_trackMaker->createDkfTrack(*(pT->siSpacePoints()),vpTrkNodes, m_DChi2);
+  if(!trackResult) 
+    {
+			ATH_MSG_DEBUG("TrigDkfTrackMaker failed");
+      return StatusCode::FAILURE;
+    }
+
+  int nNodeIndex=-1;
+  bool OK=true;
+  std::vector<Trk::TrkBaseNode*>::iterator pnIt,pnEnd(vpTrkNodes.end());
+ 
+  for(std::vector<Trk::TrkBaseNode*>::iterator pNodeIt=vpTrkNodes.begin();pNodeIt!=vpTrkNodes.end();
+      ++pNodeIt)
+    {
+      nNodeIndex++;
+      Trk::TrkBaseNode* pMaskedNode=(*pNodeIt);
+      Trk::TrkTrackState* pMaskedState=NULL;
+
+      // 2. Create initial track state:
+      
+      Rk[0]=param->a0();
+      Rk[1]=param->z0();
+      Rk[2]=param->phi0();
+      Theta=2.0*atan(exp(-param->eta()));
+      Rk[3]=Theta;
+      Rk[4]=sin(Theta)/param->pT();
+  
+      // 3. Main algorithm: filter and smoother (Rauch-Tung-Striebel)
+      
+      Trk::TrkTrackState* pTS = new Trk::TrkTrackState(Rk);
+      double Gk[5][5];
+      memset(&Gk[0][0],0,sizeof(Gk));
+      Gk[0][0]=100.0;Gk[1][1]=100.0;Gk[2][2]=0.01;Gk[3][3]=0.01;Gk[4][4]=1e-6;
+      pTS->m_setTrackCovariance(Gk);
+      if(m_doMultScatt)  
+	pTS->m_setScatteringMode(1);
+      if(m_doBremm)
+	pTS->m_setScatteringMode(2);
+      vpTrackStates.push_back(pTS);
+
+			ATH_MSG_DEBUG("Initial params: locT="<<Rk[0]<<" locL="<<Rk[1]<<" phi="<<Rk[2]
+				<<" theta="<<Rk[3]<<" Q="<<Rk[4]<<" pT="<<sin(Rk[3])/Rk[4]);
+  
+      OK=true;
+      Trk::TrkPlanarSurface *pSB=NULL,*pSE;
+  
+      for(pnIt=vpTrkNodes.begin();pnIt!=pnEnd;++pnIt)
+	{
+	  pSE=(*pnIt)->m_getSurface();
+	  Trk::TrkTrackState* pNS=m_extrapolate(pTS,pSB,pSE);
+      
+	  pSB=pSE;
+	  if(pNS!=NULL)
+	    {
+	      vpTrackStates.push_back(pNS);
+	  
+	      (*pnIt)->m_validateMeasurement(pNS);
+				ATH_MSG_DEBUG("dChi2="<<(*pnIt)->m_getChi2());
+	      if((*pnIt)!=pMaskedNode)
+		{
+		  (*pnIt)->m_updateTrackState(pNS);
+		}
+	      else
+		{
+		  pMaskedState=pNS;
+		}
+	      pTS=pNS;
+	      Pt=sin(pTS->m_getTrackState(3))/pTS->m_getTrackState(4);
+	      if(fabs(Pt)<200.0)
+		{
+			ATH_MSG_DEBUG("Estimated Pt is too low "<<Pt<<" - skipping fit");
+		  OK=false;break;
+		}
+	    }
+	  else
+	    {
+	      OK=false;break;
+	    }
+	}
+      if(OK)
+	{
+	  std::vector<Trk::TrkTrackState*>::reverse_iterator ptsrIt(vpTrackStates.rbegin()),
+	    ptsrEnd(vpTrackStates.rend());
+
+	  for(;ptsrIt!=ptsrEnd;++ptsrIt)
+	    {
+	      (*ptsrIt)->m_runSmoother();
+	    }
+
+	  pMaskedNode->m_validateMeasurement(pMaskedState);
+	      
+	  double r[2],V[2][2];
+
+	  int nSize=pMaskedNode->m_getResiduals(r);
+	  nSize=pMaskedNode->m_getInverseResidualVariance(V);
+	  const Trk::PrepRawData* pPRD = pMaskedNode->m_getPrepRawData();
+	      
+	  Identifier id = pPRD->identify();
+	      
+	  int Region=-1;
+	  if(m_idHelper->is_pixel(id))
+	    {
+	      Region=(m_pixelId->is_barrel(id))?1:2;
+	    }
+	  if(m_idHelper->is_sct(id))
+	    {
+	      Region=(m_sctId->is_barrel(id))?3:4;
+	    }
+	  if(nSize==1) {
+	    if(V[0][0]>0.0) {
+	      vResid.push_back(TrigL2HitResidual(id,Region,r[0],r[0]*sqrt(V[0][0])));
+	    }
+	    else {
+	      OK=false;
+	      break;
+	    }
+	  }
+	  else {
+	    if((V[0][0]>0.0) && (V[1][1]>0.0)) {
+	      vResid.push_back(TrigL2HitResidual(id,Region,r[0],r[0]*sqrt(V[0][0]),
+						 r[1],r[1]*sqrt(V[1][1])));
+	    }
+	    else {
+	      OK=false;
+	      break;
+	    }
+	  }
+	}
+      else
+	{
+	  ATH_MSG_DEBUG("Forward Kalman filter: extrapolation failure ");
+	  vResid.clear();
+	}
+      for(std::vector<Trk::TrkTrackState*>::iterator ptsIt=vpTrackStates.begin();
+	  ptsIt!=vpTrackStates.end();++ptsIt) delete (*ptsIt);
+      vpTrackStates.clear();
+      if(!OK) break;
+    }
+  pnIt=vpTrkNodes.begin();pnEnd=vpTrkNodes.end();
+  for(;pnIt!=pnEnd;++pnIt) 
+    {
+      delete((*pnIt)->m_getSurface());
+      delete (*pnIt);
+    }
+  vpTrkNodes.clear();
+      
+  if(OK) return StatusCode::SUCCESS;
+  else return StatusCode::FAILURE;
+
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/components/TrigInDetTrackFitter_entries.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/components/TrigInDetTrackFitter_entries.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..174251b1f08c854289c90e46571bb27881075f61
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/components/TrigInDetTrackFitter_entries.cxx
@@ -0,0 +1,43 @@
+#include "TrigInDetTrackFitter/TrigInDetTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetPerigeeFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetSctKFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetKarimakiFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetBremDetectionTool.h"
+#include "TrigInDetTrackFitter/TrigDkfTrackMakerTool.h"
+#include "TrigInDetTrackFitter/TrigL2ResidualCalculator.h"
+#include "TrigInDetTrackFitter/TrigInDetOfflineTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigInDetCombinedTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigL2HighPtTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigL2LowPtTrackFitter.h"
+#include "TrigInDetTrackFitter/TrigL2FastExtrapolationTool.h"
+
+#include "GaudiKernel/DeclareFactoryEntries.h"
+
+DECLARE_TOOL_FACTORY(TrigInDetTrackFitter)
+DECLARE_TOOL_FACTORY(TrigInDetPerigeeFitter)
+DECLARE_TOOL_FACTORY(TrigInDetSctKFitter)
+DECLARE_TOOL_FACTORY(TrigInDetKarimakiFitter)
+DECLARE_TOOL_FACTORY(TrigInDetBremDetectionTool)
+DECLARE_TOOL_FACTORY(TrigDkfTrackMakerTool)
+DECLARE_TOOL_FACTORY(TrigL2ResidualCalculator)
+DECLARE_TOOL_FACTORY(TrigInDetOfflineTrackFitter)
+DECLARE_TOOL_FACTORY(TrigInDetCombinedTrackFitter)
+DECLARE_TOOL_FACTORY(TrigL2HighPtTrackFitter)
+DECLARE_TOOL_FACTORY(TrigL2LowPtTrackFitter)
+DECLARE_TOOL_FACTORY(TrigL2FastExtrapolationTool)
+
+DECLARE_FACTORY_ENTRIES(TrigInDetTrackFitter)
+{
+  DECLARE_TOOL(TrigInDetTrackFitter)
+  DECLARE_TOOL(TrigInDetPerigeeFitter)
+  DECLARE_TOOL(TrigInDetSctKFitter)
+  DECLARE_TOOL(TrigInDetKarimakiFitter)
+  DECLARE_TOOL(TrigInDetBremDetectionTool)
+  DECLARE_TOOL(TrigDkfTrackMakerTool)
+  DECLARE_TOOL(TrigL2ResidualCalculator)
+  DECLARE_TOOL(TrigInDetOfflineTrackFitter)
+  DECLARE_TOOL(TrigInDetCombinedTrackFitter)
+  DECLARE_TOOL(TrigL2HighPtTrackFitter)
+  DECLARE_TOOL(TrigL2LowPtTrackFitter)
+  DECLARE_TOOL(TrigL2FastExtrapolationTool)
+}
diff --git a/Trigger/TrigTools/TrigInDetTrackFitter/src/components/TrigInDetTrackFitter_load.cxx b/Trigger/TrigTools/TrigInDetTrackFitter/src/components/TrigInDetTrackFitter_load.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..871f3f548572937299ca49cb94bb5a94b24dc7b0
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetTrackFitter/src/components/TrigInDetTrackFitter_load.cxx
@@ -0,0 +1,4 @@
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES( TrigInDetTrackFitter )
+