diff --git a/.gitignore b/.gitignore
index 4ecc3356a1d4a5160682ddba2dbe3ca90b71436d..7ed00b371824a8816c3ef9d10c186352e00fef2c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@
 .project
 *.pyc
 .asetup*
+.cproject
diff --git a/Trigger/TrigFTK/FTK_DataProviderSvc/FTK_DataProviderSvc/FTK_DataProviderSvc.h b/Trigger/TrigFTK/FTK_DataProviderSvc/FTK_DataProviderSvc/FTK_DataProviderSvc.h
index bb4bdffa1f9e0e6fe3ed806ddbe35ec721d5dc9d..9a161d563921673ec4f58f92e18efa2ad62367e6 100644
--- a/Trigger/TrigFTK/FTK_DataProviderSvc/FTK_DataProviderSvc/FTK_DataProviderSvc.h
+++ b/Trigger/TrigFTK/FTK_DataProviderSvc/FTK_DataProviderSvc/FTK_DataProviderSvc.h
@@ -32,6 +32,7 @@
 #include "xAODTracking/VertexContainer.h"
 #include "xAODTracking/TrackParticleContainer.h"
 #include "FTK_DataProviderInterfaces/IFTK_UncertaintyTool.h"
+#include "FTK_RecToolInterfaces/IFTK_DuplicateTrackRemovalTool.h"
 
 /// Forward Declarations ///
 class AtlasDetectorID;
@@ -173,14 +174,16 @@ class FTK_DataProviderSvc : public virtual IFTK_DataProviderSvc, virtual public
   ToolHandle< InDet::IVertexFinder > m_VertexFinderTool;
   ToolHandle< IFTK_VertexFinderTool > m_RawVertexFinderTool;
   ToolHandle< Trk::IRIO_OnTrackCreator >      m_ROTcreator;
+  ToolHandle< IFTK_DuplicateTrackRemovalTool > m_DuplicateTrackRemovalTool;
 
   double m_trainingBeamspotX;
   double m_trainingBeamspotY;
   double m_trainingBeamspotZ;
   double m_trainingBeamspotTiltX;
   double m_trainingBeamspotTiltY;
-
-
+  
+  bool m_remove_duplicates;
+  
   const FTK_RawTrackContainer* m_ftk_tracks;
 
   // Track Cache
diff --git a/Trigger/TrigFTK/FTK_DataProviderSvc/src/FTK_DataProviderSvc.cxx b/Trigger/TrigFTK/FTK_DataProviderSvc/src/FTK_DataProviderSvc.cxx
index 46d3a13a98a4ea447b59af9fcad5b5d72d45309b..d4541bd9c11396cb5c020ba28c93bce393d3ef91 100644
--- a/Trigger/TrigFTK/FTK_DataProviderSvc/src/FTK_DataProviderSvc.cxx
+++ b/Trigger/TrigFTK/FTK_DataProviderSvc/src/FTK_DataProviderSvc.cxx
@@ -53,6 +53,7 @@
 #include "PixelConditionsServices/IPixelOfflineCalibSvc.h"
 #include "TrkToolInterfaces/ITrackSummaryTool.h"
 #include "TrkTrackSummary/TrackSummary.h"
+#include "FTK_RecToolInterfaces/IFTK_DuplicateTrackRemovalTool.h"
 #include "FTK_RecToolInterfaces/IFTK_VertexFinderTool.h"
 #include "FTK_DataProviderInterfaces/IFTK_UncertaintyTool.h"
 
@@ -102,11 +103,13 @@ FTK_DataProviderSvc::FTK_DataProviderSvc(const std::string& name, ISvcLocator* s
   m_VertexFinderTool("InDet::InDetIterativePriVxFinderTool"),
   m_RawVertexFinderTool("FTK_VertexFinderTool"),
   m_ROTcreator("Trk::IRIO_OnTrackCreator/FTK_ROTcreatorTool"),
+  m_DuplicateTrackRemovalTool("FTK_DuplicateTrackRemovalTool"),
   m_trainingBeamspotX(0.),
   m_trainingBeamspotY(0.),
   m_trainingBeamspotZ(0.),
   m_trainingBeamspotTiltX(0.),
   m_trainingBeamspotTiltY(0.),
+  m_remove_duplicates(false),
   m_ftk_tracks(nullptr),
   m_conv_tracks(nullptr),
   m_refit_tracks(nullptr),
@@ -181,6 +184,7 @@ FTK_DataProviderSvc::FTK_DataProviderSvc(const std::string& name, ISvcLocator* s
   declareProperty("TrackFitter", m_trackFitter);
   declareProperty("UncertaintyTool",m_uncertaintyTool);
   declareProperty("TrackSummaryTool", m_trackSumTool);
+  declareProperty("DuplicateTrackRemovalTool",m_DuplicateTrackRemovalTool);
   declareProperty("TrackParticleCreatorTool", m_particleCreatorTool);
   declareProperty("VertexFinderTool",m_VertexFinderTool);
   declareProperty("ROTcreatorTool",m_ROTcreator);
@@ -208,7 +212,7 @@ FTK_DataProviderSvc::FTK_DataProviderSvc(const std::string& name, ISvcLocator* s
   declareProperty("CorrectSCTClusters",m_correctSCTClusters);
   declareProperty("setBroadPixelClusterOnTrackErrors",m_broadPixelErrors);
   declareProperty("setBroadSCT_ClusterOnTrackErrors",m_broadSCT_Errors);
-
+  declareProperty("RemoveDuplicates",m_remove_duplicates);
 
 
 }
@@ -271,6 +275,8 @@ StatusCode FTK_DataProviderSvc::initialize() {
   ATH_CHECK(m_particleCreatorTool.retrieve());
   ATH_MSG_INFO( " getting vertexFinderTool tool with name " << m_VertexFinderTool.name());
   ATH_CHECK(m_VertexFinderTool.retrieve());
+  ATH_MSG_INFO( " getting DuplicateTrackRemovalTool tool with name " << m_DuplicateTrackRemovalTool.name());
+  ATH_CHECK(m_DuplicateTrackRemovalTool.retrieve());
   ATH_MSG_INFO( " getting FTK_RawTrackVertexFinderTool tool with name " << m_RawVertexFinderTool.name());
   ATH_CHECK(m_RawVertexFinderTool.retrieve());
   ATH_MSG_INFO( " getting ROTcreator tool with name " << m_ROTcreator.name());
@@ -1142,23 +1148,33 @@ void FTK_DataProviderSvc::getFTK_RawTracksFromSG(){
   }
 
   // new event - get the tracks from StoreGate
-
   if (!m_storeGate->contains<FTK_RawTrackContainer>(m_RDO_key)) {
-    ATH_MSG_DEBUG( "getFTK_RawTracksFromSG: FTK tracks  "<< m_RDO_key <<" not found in StoreGate !");
-    return;
-  } else {
-    ATH_MSG_VERBOSE( "getFTK_RawTracksFromSG:  Doing storegate retreive");
-    StatusCode sc = m_storeGate->retrieve(m_ftk_tracks, m_RDO_key);
-    if (sc.isFailure()) {
-      ATH_MSG_VERBOSE( "getFTK_RawTracksFromSG: Failed to get FTK Tracks Container");
-      return;
-    }
-    ATH_MSG_DEBUG( "getFTK_RawTracksFromSG:  Got " << m_ftk_tracks->size() << " raw FTK tracks (RDO) from  StoreGate ");
-    m_gotRawTracks = true;
-
+	  ATH_MSG_DEBUG( "getFTK_RawTracksFromSG: FTK tracks  "<< m_RDO_key <<" not found in StoreGate !");
+	  return;
+  } else {    
+	  if (m_remove_duplicates){//get all tracks, and then call duplicate removal tool
+		  const FTK_RawTrackContainer* temporaryTracks=nullptr;
+		  StatusCode sc = m_storeGate->retrieve(temporaryTracks, m_RDO_key);
+		  ATH_MSG_DEBUG( "getFTK_RawTracksFromSG:  Got " << temporaryTracks->size() << " raw FTK tracks (RDO) from  StoreGate ");
+		  m_ftk_tracks = m_DuplicateTrackRemovalTool->removeDuplicates(temporaryTracks);
+		  if (sc.isFailure()) {
+			  ATH_MSG_WARNING( "getFTK_RawTracksFromSG: Failed to get FTK Tracks Container when using removeDumplicates ");
+			  return;
+		  }
+	  }
+	  else{//the original way
+		  ATH_MSG_VERBOSE( "getFTK_RawTracksFromSG:  Doing storegate retrieve");
+		  StatusCode sc = m_storeGate->retrieve(m_ftk_tracks, m_RDO_key);
+		  if (sc.isFailure()) {
+			  ATH_MSG_WARNING( "getFTK_RawTracksFromSG: Failed to get FTK Tracks Container");
+			  return;
+		  }
+	  }
+	  ATH_MSG_DEBUG( "getFTK_RawTracksFromSG:  Got " << m_ftk_tracks->size() << " raw FTK tracks");
+	  m_gotRawTracks = true;
   }
+  
   // Creating collection for pixel clusters
-
   m_PixelClusterContainer = new InDet::PixelClusterContainer(m_pixelId->wafer_hash_max());
   m_PixelClusterContainer->addRef();
   StatusCode sc = m_storeGate->record(m_PixelClusterContainer,m_PixelClusterContainerName);
@@ -1339,7 +1355,7 @@ Trk::Track* FTK_DataProviderSvc::ConvertTrack(const unsigned int iTrack){
   // Find if the track includes IBL - needed for the error calculaton 
   for( unsigned int cluster_number = 0; cluster_number < track.getPixelClusters().size(); ++cluster_number){
     if ( !track.isMissingPixelLayer(cluster_number)) {
-      Identifier wafer_id = m_pixelId->wafer_id(track.getPixelClusters()[cluster_number].getModuleID());
+      Identifier wafer_id = m_pixelId->wafer_id(Identifier(track.getPixelClusters()[cluster_number].getModuleID()));
       if (m_pixelId->barrel_ec(wafer_id)==0 && m_pixelId->layer_disk(wafer_id)==0) {
 	hasIBL=true;
 	break;
diff --git a/Trigger/TrigFTK/FTK_RecToolInterfaces/FTK_RecToolInterfaces/IFTK_DuplicateTrackRemovalTool.h b/Trigger/TrigFTK/FTK_RecToolInterfaces/FTK_RecToolInterfaces/IFTK_DuplicateTrackRemovalTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc4fbffa813afd924436d23d9d18e2cd873c901f
--- /dev/null
+++ b/Trigger/TrigFTK/FTK_RecToolInterfaces/FTK_RecToolInterfaces/IFTK_DuplicateTrackRemovalTool.h
@@ -0,0 +1,25 @@
+
+//abstract interface
+
+#ifndef __IFTK_DUPLICATETRACKREMOVAL_TOOL_H__
+#define __IFTK_DUPLICATETRACKREMOVAL_TOOL_H__
+
+#include "GaudiKernel/IAlgTool.h"
+#include "TrigFTK_RawData/FTK_RawTrackContainer.h"
+
+static const InterfaceID IID_IFTK_DuplicateTrackRemovalTool("IFTK_DuplicateTrackRemovalTool",1,0);
+
+class IFTK_DuplicateTrackRemovalTool : virtual public IAlgTool { 
+
+ public:
+  /** other standard AlgTool methods */
+  static const InterfaceID& interfaceID ()   //!< the Tool's interface
+  {  return IID_IFTK_DuplicateTrackRemovalTool; }  	
+
+  virtual FTK_RawTrackContainer* removeDuplicates(const FTK_RawTrackContainer* trks) = 0;
+
+ private:
+
+};
+
+#endif
diff --git a/Trigger/TrigFTK/FTK_RecTools/FTK_RecTools/FTK_DuplicateTrackRemovalTool.h b/Trigger/TrigFTK/FTK_RecTools/FTK_RecTools/FTK_DuplicateTrackRemovalTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..45f4f573350175b857503eb7059a3f00b6b5b02f
--- /dev/null
+++ b/Trigger/TrigFTK/FTK_RecTools/FTK_RecTools/FTK_DuplicateTrackRemovalTool.h
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// FTK_DuplicateTrackRemovalTool tool
+// -------------------------------
+// Remove duplicate (overlapping) tracks
+// June 2017: Tool created
+// Author: Andy Haas, NYU
+// e-mail: ahaas@cern.ch
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __TRIG_FTK_DUPLICATETRACKREMOVAL_TOOL_H__
+#define __TRIG_FTK_DUPLICATETRACKREMOVAL_TOOL_H__
+
+#include "GaudiKernel/ToolHandle.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "FTK_RecToolInterfaces/IFTK_DuplicateTrackRemovalTool.h"
+#include "TrigFTK_RawData/FTK_RawTrackContainer.h"
+#include <map>
+
+//#define FTKDuplicateTrackRemovalTiming
+#define FTKDuplicateTrackRemovalUseMap
+//#define FTKDuplicateTrackRemovalTestMultiple
+
+class FTK_DuplicateTrackRemovalTool : public AthAlgTool, virtual public IFTK_DuplicateTrackRemovalTool
+{
+ public:
+  FTK_DuplicateTrackRemovalTool( const std::string&, const std::string&, const IInterface* );
+  virtual ~FTK_DuplicateTrackRemovalTool(){};
+  virtual StatusCode initialize();
+  virtual  StatusCode finalize  ();
+  FTK_RawTrackContainer* removeDuplicates(const FTK_RawTrackContainer* trks);
+ private:
+    FTK_RawTrackContainer* m_trks_nodups;
+    bool match(const FTK_RawTrack* track, const FTK_RawTrack* oldtrack) const;
+    const FTK_RawTrack* besttrack(const FTK_RawTrack* track, const FTK_RawTrack* oldtrack) const;
+    int m_HW_ndiff;
+    double m_dphi_roughmatch;
+#ifdef FTKDuplicateTrackRemovalUseMap
+    std::map<double, std::vector<unsigned int> > phimap;//keep track of the phi of tracks in the output container - at each phi there could be a vector of track indices...
+    void addtophimap(double trackphi, unsigned int pos);
+    void removefromphimap(double trackphi, unsigned int pos);
+#endif
+};
+
+#endif
diff --git a/Trigger/TrigFTK/FTK_RecTools/src/FTK_DuplicateTrackRemovalTool.cxx b/Trigger/TrigFTK/FTK_RecTools/src/FTK_DuplicateTrackRemovalTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d4d8556e2aaad1ffa86ca04dc675b38ffc7d90d3
--- /dev/null
+++ b/Trigger/TrigFTK/FTK_RecTools/src/FTK_DuplicateTrackRemovalTool.cxx
@@ -0,0 +1,303 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FTK_RecTools/FTK_DuplicateTrackRemovalTool.h"
+#include <vector>
+#include "TVector2.h"
+#include "CLHEP/Units/PhysicalConstants.h"
+
+FTK_DuplicateTrackRemovalTool::FTK_DuplicateTrackRemovalTool(const std::string& t,
+                                               const std::string& n,
+                                               const IInterface*  p ):
+  AthAlgTool(t,n,p),
+  m_trks_nodups(NULL),
+  m_HW_ndiff(6),
+  m_dphi_roughmatch(0.3)
+{
+  declareInterface< IFTK_DuplicateTrackRemovalTool >( this );
+  declareProperty("HW_ndiff",m_HW_ndiff);
+  declareProperty("dphi_roughmatch",m_dphi_roughmatch);
+}
+
+StatusCode FTK_DuplicateTrackRemovalTool::initialize() {
+
+  StatusCode sc = AlgTool::initialize();
+  MsgStream athenaLog(msgSvc(), name());
+
+  m_trks_nodups = new FTK_RawTrackContainer(SG::VIEW_ELEMENTS);//we don't own the tracks, we're just going to hold them
+
+  athenaLog << MSG::INFO << "FTK_DuplicateTrackRemovalTool initialized "<< endmsg;
+  return sc;
+}
+
+StatusCode FTK_DuplicateTrackRemovalTool::finalize() {
+  StatusCode sc = AlgTool::finalize();
+  m_trks_nodups->clear();
+  delete m_trks_nodups;
+  return sc;
+}
+
+//tell whether the two tracks match, based on number of matching hits and unmatching hits
+bool FTK_DuplicateTrackRemovalTool::match(const FTK_RawTrack* track, const FTK_RawTrack* oldtrack) const {
+
+	const std::vector<FTK_RawPixelCluster>& pixclus = track->getPixelClusters();
+	const std::vector<FTK_RawSCT_Cluster>& sctclus = track->getSCTClusters();
+
+	//Note to self: Clusters are made from sim in FTK_RDO_CreatorAlgo...
+
+	int nclus = pixclus.size() + sctclus.size();
+	int nmatchingclus=0;
+	int nclusleft=12;// there's at most 12 hits, 4 pixel and 8 sct
+	const std::vector<FTK_RawPixelCluster>& oldpixclus = oldtrack->getPixelClusters();
+	for (auto clus : pixclus){
+		//is this pixel clus matched by any on the old track?
+		unsigned int id = clus.getModuleID();
+		for (auto oldclus : oldpixclus){
+			if (oldclus.getModuleID()==id){ // if the ID matches, it's on the same module // stored in WordA
+				if (clus.getWordB()==oldclus.getWordB()) { // is it the same eta and phi position and width? // stored in WordB
+					nmatchingclus++;
+
+					//it matches if the number of unmatched clusters is <= 6 (or HW_diff)
+					if ( (nclus-nmatchingclus) <= m_HW_ndiff){ //corresponding criteria in simulation
+						return true; //return as soon as we know the answer!
+					}
+					break; //we already found a matching cluster to this cluster, so no need to look for more matches to this cluster
+				}
+			}
+		}//loop over old tracks' clusters
+		nclusleft--;
+		if ((nclus-nmatchingclus-nclusleft)>m_HW_ndiff) return false; // no way we can get there with just nclusleft remaining
+	}
+
+	const std::vector<FTK_RawSCT_Cluster>& oldsctclus = oldtrack->getSCTClusters();
+	for (auto clus : sctclus){
+		//is this sct clus matched by any on the old track?
+		unsigned int id = clus.getWord();
+		for (auto oldclus : oldsctclus){
+			if (oldclus.getWord()==id){ // if the word matches, it's the same dude
+				nmatchingclus++;
+
+				//it matches if the number of unmatched clusters is <= 6 (or HW_diff)
+				if ( (nclus-nmatchingclus) <= m_HW_ndiff){ //corresponding criteria in simulation
+					return true; //return as soon as we know the answer!
+				}
+				break; //we already found a matching cluster to this cluster, so no need to look for more matches to this cluster
+			}
+		}//loop over old tracks' clusters
+		nclusleft--;
+		if ((nclus-nmatchingclus-nclusleft)>m_HW_ndiff) return false; // no way we can get there with just nclusleft remaining
+	}
+
+	//ATH_MSG_DEBUG("Found "<<nmatchingpixclus<<" matching pix clus out of "<<pixclus.size());
+	//ATH_MSG_DEBUG("Found "<<nmatchingsctclus<<" matching sct clus out of "<<sctclus.size());
+
+	//ATH_MSG_VERBOSE("ACH888: "<<matching<<" "<<track->getSectorID()<<" "<<track->getPhi()<<" "<<track->getCotTh()<<" "<<track->getZ0()<<" "<<oldtrack->getSectorID()<<" "<<oldtrack->getPhi()<<" "<<oldtrack->getCotTh()<<" "<<oldtrack->getZ0());
+	return false;
+}
+
+//return the better of two tracks, based on number of missing layers, and if those tie, chi2
+const FTK_RawTrack* FTK_DuplicateTrackRemovalTool::besttrack(const FTK_RawTrack* track, const FTK_RawTrack* oldtrack) const {
+	//return track;//ACH-temporary test to see if this is slow
+
+	unsigned int trackhits = track->getPixelClusters().size()+track->getSCTClusters().size();
+	unsigned int oldtrackhits = oldtrack->getPixelClusters().size()+oldtrack->getSCTClusters().size();
+	if (trackhits > oldtrackhits) return track;
+	if (oldtrackhits > trackhits) return oldtrack;
+
+	//in case of a tie, use chi2
+	if (track->getChi2() < oldtrack->getChi2()) return track; // smaller chi2 wins
+	else return oldtrack;
+}
+
+#ifdef FTKDuplicateTrackRemovalUseMap
+void FTK_DuplicateTrackRemovalTool::addtophimap(double trackphi, unsigned int pos){
+	phimap[trackphi].push_back(pos);//add it to the map
+
+	//check that track phi is within 0-2pi
+	if (trackphi<-CLHEP::pi) ATH_MSG_ERROR("FTK track with phi < -pi! "<<trackphi);
+	else if (trackphi>CLHEP::pi) ATH_MSG_ERROR("FTK track with phi > pi! "<<trackphi);
+
+	//add extra copy in case of wraparound past 0 or 2pi
+	if (trackphi>(CLHEP::pi-m_dphi_roughmatch)) phimap[trackphi-CLHEP::twopi].push_back(pos);
+	else if (trackphi<(-CLHEP::pi+m_dphi_roughmatch)) phimap[trackphi+CLHEP::twopi].push_back(pos);
+}
+void FTK_DuplicateTrackRemovalTool::removefromphimap(double oldtrackphi, unsigned int e){
+
+	//remove the old track from the map
+	auto& vec = phimap[oldtrackphi];
+	auto ind = std::find(vec.begin(),vec.end(),e);
+	if (ind==vec.end()) ATH_MSG_WARNING("Wasn't in the map?! "<<oldtrackphi<<" "<<e);
+	else vec.erase(ind);
+
+	//take of removing wraparound entries
+	if (oldtrackphi>(CLHEP::pi-m_dphi_roughmatch)) {
+		vec = phimap[oldtrackphi-CLHEP::twopi];
+		auto ind = std::find(vec.begin(),vec.end(),e);
+		if (ind==vec.end()) ATH_MSG_WARNING("Wasn't in the map?! "<<oldtrackphi<<" "<<e);
+		else vec.erase(ind);
+	}
+	else if (oldtrackphi<(-CLHEP::pi+m_dphi_roughmatch)) {
+		vec = phimap[oldtrackphi+CLHEP::twopi];
+		auto ind = std::find(vec.begin(),vec.end(),e);
+		if (ind==vec.end()) ATH_MSG_WARNING("Wasn't in the map?! "<<oldtrackphi<<" "<<e);
+		else vec.erase(ind);
+	}
+}
+#endif
+
+FTK_RawTrackContainer* FTK_DuplicateTrackRemovalTool::removeDuplicates(const FTK_RawTrackContainer* trks){
+
+#ifdef FTKDuplicateTrackRemovalTiming
+  clock_t tStart = clock();
+  for (int tim=0;tim<1000;++tim){
+#endif
+
+#ifdef FTKDuplicateTrackRemovalUseMap
+	  phimap.clear();
+	  std::set<unsigned int> trackstokill;
+#endif
+
+  ATH_MSG_DEBUG("I'm in removeDuplicates!");
+  m_trks_nodups->clear();
+  m_trks_nodups->reserve(trks->size());
+  for (unsigned int i = 0; i!=trks->size(); i++) {
+	  const FTK_RawTrack *track = trks->at(i);
+
+	  //now we should see whether this track overlaps with one (or more?) tracks already in the nodups container
+	  std::vector<unsigned int> matching_oldtracks;
+
+#ifdef FTKDuplicateTrackRemovalUseMap
+	  //search just the range of phi in the map of old tracks near the phi of this new track
+	  //the map goes from -pi-dphi_roughmatch to pi+dphi_roughmatch, to handle wraparound
+	  double trackphi = track->getPhi();
+	  auto lower = phimap.lower_bound(trackphi-m_dphi_roughmatch);
+	  auto upper = phimap.upper_bound(trackphi+m_dphi_roughmatch);
+	  for (auto it=lower; it!=upper; it++){
+		  for (unsigned int e : it->second) {//these are the indices of the old tracks at each phi value in the phi range
+			  //ATH_MSG_DEBUG("Looking for match of track "<<i<<" with oldtrack "<<e);
+			  const FTK_RawTrack *oldtrack = m_trks_nodups->at(e);
+			  if (this->match(track,oldtrack)) {
+				  matching_oldtracks.push_back(e);
+			  }
+		  }
+	  }
+#else
+	  //loop over all old tracks and see if they match
+	  for (unsigned int e = 0; e!=m_trks_nodups->size(); e++) {
+		  const FTK_RawTrack *oldtrack = m_trks_nodups->at(e);
+
+		  //first check for a rough match in phi
+		  double dphi = TVector2::Phi_mpi_pi(track->getPhi()-oldtrack->getPhi());//make sure it's in -pi..pi
+		  dphi = fabs(dphi);//then take abs since we don't care about sign
+		  if (dphi>m_dphi_roughmatch) continue;//no match if dphi is larger than dphi_roughmatch, 0.3 by default
+
+		  if (this->match(track,oldtrack)) {
+			  matching_oldtracks.push_back(e);
+		  }
+	  }
+#endif
+
+	  //ATH_MSG_DEBUG("Found "<<matching_oldtracks.size()<<" old tracks matching track "<<i);
+	  if (matching_oldtracks.size()==0){//if there's no match, just add the new track
+#ifdef FTKDuplicateTrackRemovalTestMultiple
+		  for (int j=0; j<3; ++j){ // ACH - temporary test - add multiple times, to test multiple matches!
+#endif
+#ifdef FTKDuplicateTrackRemovalUseMap
+		  addtophimap(trackphi,m_trks_nodups->size());//so e.g. the first track will be index 0, since the size is 0 just before we push_back the first track
+#endif
+		  m_trks_nodups->push_back((FTK_RawTrack*)track);
+#ifdef FTKDuplicateTrackRemovalTestMultiple
+		  } // ACH - temporary test - add multiple times, to test multiple matches!
+#endif
+	  }
+
+	  //if it does match, either replace the matching track(s) with this new track, or ignore this new track, depending on which track we like best
+	  else if (matching_oldtracks.size()==1){
+		  unsigned int e = matching_oldtracks[0];
+		  const FTK_RawTrack *oldtrack = m_trks_nodups->at(e);
+		  const FTK_RawTrack *besttrack = this->besttrack(track,oldtrack);
+		  if (besttrack==track){
+#ifdef FTKDuplicateTrackRemovalUseMap
+			  removefromphimap(oldtrack->getPhi(),e);//remove the old track from the map
+			  addtophimap(trackphi,e);//add the new track to the map
+#endif
+			  m_trks_nodups->at(e)=(FTK_RawTrack*)track;
+		  }
+		  else{
+			  //nothing to do - the better track was already in the output container
+		  }
+	  }
+
+	  else { // more than 1 matching existing track (yet the existing matching tracks did not match each other)
+		  ATH_MSG_WARNING("Found multiple tracks ("<<matching_oldtracks.size()<<") matching track "<<i);
+
+		  // is the new track better than all the matching old tracks?
+		  bool newisbest = true;//start with an optimistic attitude!
+		  for (unsigned int e : matching_oldtracks){
+			  const FTK_RawTrack *oldtrack = m_trks_nodups->at(e);
+			  const FTK_RawTrack *besttrack = this->besttrack(track,oldtrack);
+			  if (besttrack!=track){
+				  newisbest=false; // guess we're not the best, give up!
+				  break;
+			  }
+		  }
+
+		  // if the new track is better than all the matching old tracks, remove the old tracks and add this one, otherwise do nothing (the new track is dropped)
+		  if (newisbest){
+			  //yikes, we're better than all the matching old tracks
+			  bool replacedfirsttrack = false;//I want to check that the algorithm really replaces the first old track with the new one, and just once
+			  for (unsigned int e : matching_oldtracks){
+
+#ifdef FTKDuplicateTrackRemovalUseMap
+				  removefromphimap(m_trks_nodups->at(e)->getPhi(),e);
+#endif
+				  if (e==matching_oldtracks[0]) {//this should be a little faster than removing all the old matching tracks and then adding the new one
+
+#ifdef FTKDuplicateTrackRemovalUseMap
+					  addtophimap(trackphi,e);
+#endif
+					  m_trks_nodups->at(e)=(FTK_RawTrack*)track; // replace the first matching track with this new track
+					  if (replacedfirsttrack) ATH_MSG_WARNING("We already did replace the first matching track!");
+					  replacedfirsttrack=true;//just check that we really did it!
+				  }
+				  else {
+					  //remove the old matching tracks beyond the first  one
+#ifdef FTKDuplicateTrackRemovalUseMap
+					  trackstokill.insert(e);//we'll remove these from the tracks returned at the end of the day, so we don't screw up the map in the meantime
+#else
+					  m_trks_nodups->erase(m_trks_nodups->begin()+e); // yes this is really the way you remove an element from a vector, you have to pass in the iterator
+#endif
+				  }
+			  }
+			  if (!replacedfirsttrack)  ATH_MSG_WARNING("Why did I not replace the first track?!");
+
+		  } // new track is best one
+
+	  } // deciding what to do based on the number of matches
+
+  } // loop over incoming tracks
+
+#ifdef FTKDuplicateTrackRemovalUseMap
+  //remove those tracks that we flagged for killing
+  if (trackstokill.size()){
+	  ATH_MSG_WARNING("Killing an extra "<<trackstokill.size()<<" tracks from multiple matches");
+	  FTK_RawTrackContainer* trks_nodups_temp  = new FTK_RawTrackContainer(SG::VIEW_ELEMENTS);//we don't own the tracks, we're just going to hold them
+	  for (unsigned int e = 0; e!=m_trks_nodups->size(); e++) {
+		  if (std::find(trackstokill.begin(),trackstokill.end(),e)==trackstokill.end()) trks_nodups_temp->push_back((FTK_RawTrack*)m_trks_nodups->at(e));
+	  }
+	  m_trks_nodups->clear();
+	  delete m_trks_nodups;
+	  m_trks_nodups = trks_nodups_temp;
+  }
+#endif
+
+#ifdef FTKDuplicateTrackRemovalTiming
+  } // loop over doing the removal
+  clock_t tEnd = clock();
+  double elapsed_secs = double(tEnd - tStart) / CLOCKS_PER_SEC;
+  ATH_MSG_INFO("Time taken: "<<elapsed_secs<<" ms");//it's "ms", not "s", since we did 1000 times
+#endif
+
+  return m_trks_nodups;
+}
diff --git a/Trigger/TrigFTK/FTK_RecTools/src/components/FTK_RecTools_entries.cxx b/Trigger/TrigFTK/FTK_RecTools/src/components/FTK_RecTools_entries.cxx
index f376046dab2dd39d49f034fe50f97b6bb725c999..ee4c8bcdf7c0fc3635a6597d65705c74b5435457 100644
--- a/Trigger/TrigFTK/FTK_RecTools/src/components/FTK_RecTools_entries.cxx
+++ b/Trigger/TrigFTK/FTK_RecTools/src/components/FTK_RecTools_entries.cxx
@@ -3,13 +3,16 @@
 #include "FTK_RecTools/FTK_VertexFinderTool.h"
 #include "FTK_RecTools/FTK_PixelClusterOnTrackTool.h"
 #include "FTK_RecTools/FTK_SCTClusterOnTrackTool.h"
+#include "FTK_RecTools/FTK_DuplicateTrackRemovalTool.h"
 
 DECLARE_TOOL_FACTORY(FTK_VertexFinderTool)
 DECLARE_TOOL_FACTORY(FTK_PixelClusterOnTrackTool)
 DECLARE_TOOL_FACTORY(FTK_SCTClusterOnTrackTool)
+DECLARE_TOOL_FACTORY(FTK_DuplicateTrackRemovalTool)
 
 DECLARE_FACTORY_ENTRIES(FTK_RecTools) {
   DECLARE_TOOL(FTK_VertexFinderTool)
   DECLARE_TOOL(FTK_PixelClusterOnTrackTool)
   DECLARE_TOOL(FTK_SCTClusterOnTrackTool)
+  DECLARE_TOOL(FTK_DuplicateTrackRemovalTool)
 }