From 7d95fab69f787652fc87380c3288c521d36e3f4f Mon Sep 17 00:00:00 2001
From: John Baines <john.baines@cern.ch>
Date: Wed, 22 May 2019 19:09:22 +0200
Subject: [PATCH] Update packages:FastTrackSimWrap TrigFTKBankGen TrigFTKPool
 TrigFTKSim TrigFTKToolInterfaces TrigFTKTrackConverter
 FTKStandaloneMonitoring  from upstream/21.3 to upstream/master via
 pseudo-merge

---
 .../FTKStandaloneMonitoring/CMakeLists.txt    |   12 +-
 .../CompareFTKEvents.h                        |  131 +-
 .../CompareFTKTracks.h                        |   45 +-
 .../src/CompareFTKEvents.cxx                  |  575 ++--
 .../src/CompareFTKTracks.cxx                  |   18 +-
 .../test/MonitoringComparison.cxx             |   41 +-
 .../TrigFTK/FastTrackSimWrap/CMakeLists.txt   |    2 +
 .../FastTrackSimWrap/FTKRegionalWrapper.h     |   27 +-
 ...owersIBL3DTest_DFTestVectors_jobOptions.py |    2 +
 ...Wrap_64TowersIBL3D_HWModeID2_jobOptions.py |    4 +-
 .../src/FTKRegionalWrapper.cxx                | 1204 ++++----
 .../TrigFTKBankGen/FTKBankGenAlgo.h           |    1 +
 .../TrigFTKBankGen/FTKConstGenAlgo.h          |    4 +
 .../TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h  |   43 +
 .../TrigFTKBankGen/FTKGhostHitCalculator.h    |  143 +
 .../share/skeleton.FTKConstantGen.py          |    1 -
 .../share/skeleton.FTKMatrixReduction.py      |    3 +
 .../TrigFTKBankGen/src/FTKBankGenAlgo.cxx     |   47 +-
 .../src/FTKCachedBankGenAlgo.cxx              |    2 +
 .../TrigFTKBankGen/src/FTKConstGenAlgo.cxx    |   47 +-
 .../src/FTKDataMatrixFromMCAlgo.cxx           |  696 +++++
 .../src/FTKGhostHitCalculator.cxx             |  647 +++++
 .../TrigFTKBankGen/src/FTKPattGenRoot.cxx     |    5 +-
 .../TrigFTKBankGen/src/FTKPattGenRootAlgo.cxx |   48 +-
 .../TrigFTKBankGen/src/FTKSectorSlice.cxx     |   26 +-
 .../TrigFTKBankGen/src/PattMergeRootAlgo.cxx  |   11 +-
 .../src/components/TrigFTKBankGen_entries.cxx |   13 +-
 .../src/components/TrigFTKBankGen_load.cxx    |    6 +
 .../src/FTKTrackFitterStats_p1.cxx            |    5 +-
 Trigger/TrigFTK/TrigFTKSim/CMakeLists.txt     |   23 +-
 .../TrigFTKSim/FTKClusteringEngine.h          |  317 +++
 .../TrigFTKSim/FTKClusteringPrintout.h        |   61 +
 .../TrigFTKSim/TrigFTKSim/FTKConstantBank.h   |   14 +-
 .../TrigFTKSim/TrigFTKSim/FTKDataInput.h      |    5 +-
 .../TrigFTKSim/TrigFTKSim/FTKLogging.h        |    2 +
 .../TrigFTKSim/FTKPatternBySector.h           |    6 +-
 .../TrigFTK/TrigFTKSim/TrigFTKSim/FTKRawHit.h |    1 -
 .../TrigFTKSim/TrigFTKSim/FTKRoadFinderAlgo.h |    7 +-
 .../TrigFTKSim/TrigFTKSim/FTKRootFile.h       |    3 +-
 .../TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrack.h  |   31 +-
 .../TrigFTKSim/FTKTrackFileOutput.h           |    6 +
 .../TrigFTKSim/FTKTrackFitterAlgo.h           |    6 +-
 .../TrigFTKSim/TrigFTKSim/FTKTrackOutput.h    |    6 +
 .../TrigFTKSim/TrigFTKSim/FTKTrackStream.h    |   27 +-
 .../TrigFTKSim/FTK_CompressedAMBank.h         |  231 +-
 .../TrigFTKSim/FTK_CompressedPatternList.h    |  396 +++
 .../FTK_CompressedSectorPatternList.h         |   50 +
 .../TrigFTKSim/TrigFTKSim/FTK_HitMask.h       |   71 +
 .../TrigFTKSim/TrigFTKSim/FTK_RawInput.h      |    2 +-
 .../TrigFTKSim/TrigFTKSim/FTK_SGTrackOutput.h |   10 +
 .../TrigFTKSim/TrigFTKSim/TrackFitter.h       |   41 +-
 .../TrigFTKSim/TrigFTKSim/TrackFitter711.h    |    3 +-
 .../TrigFTKSim/TrigFTKSim/atlClustering.h     |   92 -
 .../TrigFTK/TrigFTKSim/TrigFTKSim/ftkdefs.h   |   14 +-
 .../TrigFTKSim/python/FTKSimOptions.py        |   41 +-
 .../TrigFTKSim/scripts/TrigFTKSim_tf.py       |    2 +-
 .../share/FTKCompleteSim_joboptions.py        |    3 +-
 .../TrigFTKSim/share/FTKSim_joboptions.py     |    3 +-
 .../share/skeleton.BS_FTK_Creator.py          |   13 +-
 .../share/skeleton.FTKStandaloneSim.py        |   42 +-
 .../share/skeleton.RDO_FTK_Creator.py         |    8 +
 .../TrigFTKSim/src/FTKClusteringEngine.cxx    | 1247 +++++++++
 .../TrigFTKSim/src/FTKClusteringPrintout.cxx  |   93 +
 .../TrigFTKSim/src/FTKConstantBank.cxx        |  340 ++-
 .../TrigFTK/TrigFTKSim/src/FTKDataInput.cxx   |  547 ++--
 .../TrigFTK/TrigFTKSim/src/FTKMergerAlgo.cxx  |   50 +-
 .../TrigFTKSim/src/FTKPatternBySector.cxx     |   10 +-
 .../TrigFTKSim/src/FTKRoadFinderAlgo.cxx      |   20 +-
 Trigger/TrigFTK/TrigFTKSim/src/FTKTrack.cxx   |  198 +-
 .../TrigFTKSim/src/FTKTrackFileOutput.cxx     |   27 +
 .../TrigFTKSim/src/FTKTrackFitterAlgo.cxx     |   33 +-
 .../TrigFTK/TrigFTKSim/src/FTKTrackStream.cxx |   82 +-
 Trigger/TrigFTK/TrigFTKSim/src/FTK_AMBank.cxx |    1 -
 .../TrigFTKSim/src/FTK_AMsimulation_base.cxx  |   54 +-
 .../TrigFTKSim/src/FTK_CompressedAMBank.cxx   | 2487 +++++++----------
 .../src/FTK_CompressedPatternList.cxx         |  145 +
 .../src/FTK_CompressedSectorPatternList.cxx   |  217 ++
 .../TrigFTK/TrigFTKSim/src/FTK_HitMask.cxx    |   45 +
 .../TrigFTK/TrigFTKSim/src/FTK_RawInput.cxx   |    2 +-
 .../TrigFTKSim/src/FTK_RegionalRawInput.cxx   |   35 +-
 .../TrigFTKSim/src/FTK_SGTrackOutput.cxx      |  235 +-
 Trigger/TrigFTK/TrigFTKSim/src/RoadFinder.cxx |    1 +
 .../TrigFTK/TrigFTKSim/src/TrackFitter.cxx    |  496 ++--
 .../TrigFTK/TrigFTKSim/src/TrackFitter711.cxx |  461 +--
 .../TrigFTK/TrigFTKSim/src/atlClustering.cxx  | 2065 --------------
 .../src/components/TrigFTKSim_entries.cxx     |    3 +
 .../TrigFTK/TrigFTKSim/src/tsp/FTKTSPBank.cxx |    3 +
 .../TrigFTK/TrigFTKSim/standalone/dataflow.cc |  157 +-
 .../TrigFTK/TrigFTKSim/standalone/dataflow.h  |   13 +-
 .../TrigFTKSim/standalone/efficiency.cc       |  252 +-
 .../TrigFTKSim/standalone/efficiency.h        |   15 +-
 .../standalone/efficiency_step_by_step.cc     |  835 ++++++
 .../standalone/efficiency_step_by_step.h      |  172 ++
 .../TrigFTKSim/standalone/make_conn.cc        |  232 ++
 .../standalone/makecompressedbank.cc          |  284 +-
 .../standalone/partitionbalancing.cc          |  400 ++-
 .../TrigFTKSim/standalone/patternbankinfo.cc  |  199 +-
 97 files changed, 10688 insertions(+), 6114 deletions(-)
 create mode 100644 Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h
 create mode 100644 Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKGhostHitCalculator.h
 create mode 100644 Trigger/TrigFTK/TrigFTKBankGen/src/FTKDataMatrixFromMCAlgo.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKBankGen/src/FTKGhostHitCalculator.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_load.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringEngine.h
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringPrintout.h
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedPatternList.h
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedSectorPatternList.h
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_HitMask.h
 delete mode 100644 Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/atlClustering.h
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringEngine.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringPrintout.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedPatternList.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedSectorPatternList.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/src/FTK_HitMask.cxx
 delete mode 100644 Trigger/TrigFTK/TrigFTKSim/src/atlClustering.cxx
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.cc
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.h
 create mode 100644 Trigger/TrigFTK/TrigFTKSim/standalone/make_conn.cc

diff --git a/Trigger/TrigFTK/FTKStandaloneMonitoring/CMakeLists.txt b/Trigger/TrigFTK/FTKStandaloneMonitoring/CMakeLists.txt
index 95b3af9cda0f..6777d2519d7e 100644
--- a/Trigger/TrigFTK/FTKStandaloneMonitoring/CMakeLists.txt
+++ b/Trigger/TrigFTK/FTKStandaloneMonitoring/CMakeLists.txt
@@ -11,18 +11,22 @@ atlas_depends_on_subdirs( PUBLIC
 
 # External dependencies:
 find_package( tdaq-common COMPONENTS eformat_write ) 
+find_package( tdaq COMPONENTS rc_RunController ipc omnithread omniORB4 rc RunControl rc_OnlSvc ohroot oh cmdline is owl)
 
 atlas_add_library(FTKStandaloneMonitoring
                   src/*.cxx
                   PUBLIC_HEADERS FTKStandaloneMonitoring
-                  PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                  LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES}   ByteStreamData   TrigFTK_RawData TrigFTKSimLib TrigInDetAnalysisUtils TrigInDetAnalysis TrigFTK_RawData
+
+                  PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${TDAQ_INCLUDE_DIRS}
+                  LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES}  ByteStreamData   TrigFTK_RawData TrigFTKSimLib TrigInDetAnalysisUtils TrigInDetAnalysis TrigFTK_RawData
+
                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} )
 
 atlas_add_executable(MonitoringFTKHWSWComparison
                      test/MonitoringComparison.cxx
-                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES}   ByteStreamData TrigFTK_RawData TrigFTKSimLib TrigInDetAnalysisUtils TrigInDetAnalysis TrigFTK_RawData FTKStandaloneMonitoring
+
+                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${TDAQ_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES}  ${TDAQ_LIBRARIES} ByteStreamData TrigFTK_RawData TrigFTKSimLib TrigInDetAnalysisUtils TrigInDetAnalysis TrigFTK_RawData FTKStandaloneMonitoring 
 		     )
 
 atlas_install_headers( FTKStandaloneMonitoring )
diff --git a/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKEvents.h b/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKEvents.h
index ab079a01cab7..1af1a2e2bb74 100644
--- a/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKEvents.h
+++ b/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKEvents.h
@@ -4,6 +4,34 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 #ifndef FTKSTANDALONEMONITORING_COMPAREFTKEVENTS_H
 #define FTKSTANDALONEMONITORING_COMPAREFTKEVENTS_H
 
+////////////////////////////////////////////////////////////////////
+///
+/// This class aims to get the event-by-event comparison
+/// of two files one containing HW FTK tracks (BS/RAW file)
+/// the other containing simulated (SW) FTK tracks (NTUP_FTK file)
+/// The comparison output consits of histograms published on OH,
+/// if the partition is set-up, or by histograms saved in the 
+/// out.histo.root file.
+///
+/// There are 4 types of histograms:
+/// HWSW*: if HW and SW tracks are completely matched, i.e. have the same track parameters within 0.1% of relative error
+/// 	  the distrubutions of the track paramters (like pt, eta, ...) are displayed in the histograms
+/// HWonly*: if HW tracks do not have SW tracks within m_dmax=0.2, 
+/// 	    the distrubutions of these HW track paramters (like pt, eta, ...) are displayed in the histograms
+/// SWonly*: if SW tracks do not have HW tracks within m_dmax=0.2, 
+/// 	    the distrubutions of these SW track paramters (like pt, eta, ...) are displayed in the histograms
+/// HWvsSW: if HW and SW tracks are not completely matched, 
+/// 	    i.e. they are geometrically closed but do not have the same track parameters
+/// 	    these histograms in turn are divided into :
+/// 	    HWvsSWsw*: the distrubutions of the SW track paramters (like pt, eta, ...) are displayed in the histograms
+/// 	    HWvsSWhw*: the distrubutions of the HW track paramters (like pt, eta, ...) are displayed in the histograms
+/// 	    HWvsSWdiff*: the distrubutions of the difference btw the HW and SW track paramters (like pt, eta, ...) 
+/// 			 are displayed in the histograms
+/// other general histos are 
+/// nTrk_SW: number of SW tracks per event
+/// nTrk_HW: number of HW tracks per event
+///
+////////////////////////////////////////////////////////////////////
 
 #include <iostream>
 #include <fstream>
@@ -14,7 +42,6 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 #include "TTree.h"
 #include "TFile.h"
 
-
 #include "ByteStreamData/RawEvent.h"
 #include "TrigFTKSim/FTKTrackStream.h"
 #include "TrigFTK_RawData/FTK_RawTrackContainer.h"
@@ -22,45 +49,76 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 #include "TrigFTK_RawData/FTK_RawSCT_Cluster.h"
 #include "FTKStandaloneMonitoring/FTKTrkAssoc.h"
 #include "FTKStandaloneMonitoring/CompareFTKTracks.h"
+#undef PACKAGE_VERSION
+#include "RunControl/Common/OnlineServices.h"
+#include "RunControl/Common/Exceptions.h"
+
+class IPCPartition;
+class TFile;
+class TTree;
+
 class CompareFTKEvents{
+
   public:
     CompareFTKEvents();
+    /// initialization with the path/namefile string of the HW (BS/RAW) and SW (NTUP_FTK) files
     CompareFTKEvents(const std::string &BSfile, const std::string &NTUP_FTK_file);
-    std::streampos readBSevent(int ievent,std::streampos startbufpos);
-    void readNTUP_FTKfile();
-    void PrintFiles();
-    void EventLoop();
+    
+   /// setting up partition
+   std::unique_ptr<const IPCPartition*> GetIPCPartition(const std::string& partition_name);
+       
+    /// function to read each BS event given the pointer position where it last stopped reading the event
+    std::streampos readBSevent(int ievent,std::streampos startbufpos, std::vector<uint32_t>& data);
+    
+    /// reading the SW NTUP_FTK TTrees which should contain some TTrees: 
+    ///  "evtinfo" containing basic event infos, 
+    ///  "ftkdata" containing a branch of FTKTrackStream objects with name "FTKMergedTracksStream"
+    bool readNTUP_FTKfile(const std::string& FTKfile);
+    
+    /// Get the total number of events in the BS file
+    bool read_BSfile(const std::string& BSfile);
+    
+    /// Looping over events of the HW (BS_FTK) and SW (NTUP_FTK files) and collecting track info
+    void ExecuteEventLoop(int evtmax=0);
+    
+    /// histogram initialization: for the naming convention see CompareFTKEvents.h
     void SetHistos(std::vector<std::string> histo_list);
-    void SetEvtInfoString(std::string &str_tree_evtinfo){m_str_tree_evtinfo=str_tree_evtinfo;}
-    void SetTreeNTUPString(std::string &str_tree_ftkdata){m_str_tree_ftkdata=str_tree_ftkdata;}
-    void SetBranchString(std::string &str_tree_ftkstream){m_str_tree_ftkstream=str_tree_ftkstream;}
+    
+    /// set verbose
     void SetVerbose(){m_verbose=true;}
-    void SetNEvents(int nevtmax){m_nevtmax=nevtmax;}
-    void Execute();
-    int GetNEventsBS();
+
+    /// writing histograms into file and/or publishing on OH
+    void WriteHistosToFile(const std::string& filename = "out.histo.root");
+    void PublishHistosToPartition(const std::string& partition_name = "");
+
+    /// destructor that prints out if the tracks were all matched or differences were found
     ~CompareFTKEvents();
   private:
-    StatusCode decode(uint32_t nTracks, OFFLINE_FRAGMENTS_NAMESPACE::PointerType rodData, FTK_RawTrackContainer* result);
+
+    /// decoding functions from FTKByteStreamDecoderEncoder of package Trigger/TrigFTK/TrigFTKByteStream
+    void decode(uint32_t nTracks, OFFLINE_FRAGMENTS_NAMESPACE::PointerType rodData, FTK_RawTrackContainer* result);
+
+    /// decoding functions from FTKByteStreamDecoderEncoder to get track info from BS
     FTK_RawTrack* unpackFTTrack( OFFLINE_FRAGMENTS_NAMESPACE::PointerType data);
+
+    /// decoding functions from FTKByteStreamDecoderEncoder **never tested** and **never used**
     void unpackPixCluster(OFFLINE_FRAGMENTS_NAMESPACE::PointerType data, FTK_RawPixelCluster& cluster);
-    void unpackSCTCluster(OFFLINE_FRAGMENTS_NAMESPACE::PointerType data, FTK_RawSCT_Cluster& cluster) { cluster.setWord(*data); }
-    int m_nevtmax=0;
-    static const size_t TRACKBLOBSIZE = 22; // magic number from BS specification
-    static const size_t TRACKPARAMSBLOBSIZE = 6; // --||--
-    static const size_t PIXHITPARAMSBLOBSIZE = 2; // --||--
-    static const size_t SCTHITPARAMSBLOBSIZE = 1; // --||--
-    static const size_t NPIXLAYERS=4;
-    static const size_t NSCTLAYERS=8;
-    std::vector<uint32_t> m_data;
-    std::string m_BSfile;
-    std::string m_NTUP_FTK_file;
-    uint32_t m_checkword=0xaa1234aa;
+    
+    /// decoding functions from FTKByteStreamDecoderEncoder **never tested** and **never used**
+    void unpackSCTCluster(OFFLINE_FRAGMENTS_NAMESPACE::PointerType data, FTK_RawSCT_Cluster& cluster) {cluster.setWord(*data);}
+    
+    static const size_t m_TrackBlobSize = 22; // magic number from BS specification
+    static const size_t m_TrackParamsBlobSize = 6; // --||--
+    static const size_t m_PixHitParamsBlobSize = 2; // --||--
+    static const size_t m_SCTHitParamsBlobSize = 1; // --||--
+    static const size_t m_NPixLayers=4;
+    static const size_t m_NSCTLayers=8;
+    static const uint32_t m_checkword=0xaa1234aa;
+   //std::vector<uint32_t> m_data;
     uint32_t m_trackBlockOffsetStart=0;	  // Nr of words in ROB data block before track blocks start
     uint32_t m_trackBlockOffsetEnd=0;	  // Nr of words in ROB data block after track blocks end
     int m_Nevents_BS;
-    int m_Nevents_NTUPFTK;
     std::ifstream m_myBSfile;
-    std::streampos m_tmpbufpos=0;
     TTree *m_tevtinfo;
     TTree *m_theTree;
     TFile *m_fntupftk;
@@ -68,18 +126,12 @@ class CompareFTKEvents{
     FTKTrackStream *m_ft;
     bool m_allmatched=true;
     bool m_verbose=false;
-    bool m_setup_partition=false;
-    CompareFTKTracks * m_compTrk;
+    //bool m_setup_partition=false;
+   //std::string m_partition_name;
+    CompareFTKTracks* m_compTrk;
     std::vector<std::string> m_histo_list;
     std::map<std::string , TH1D * > m_map_histo;
     std::map<std::string , TH2D * > m_map_histo_2D;
-    TFile * m_fout;
-    void CreateHistos();
-    void WriteHistos();
-    std::string m_str_tree_evtinfo="evtinfo";
-    std::string m_str_tree_ftkdata="ftkdata";
-    std::string m_str_tree_ftkstream="FTKMergedTracksStream";
-    std::string m_partition_name="";
     std::map<std::string, std::vector<double> > m_histo_param={{"pt",{1000.,0.,100000.}},
                                                               {"eta",{100.,-2.5,2.5}},
 							      {"phi",{100.,-3.2,3.2}},
@@ -87,6 +139,15 @@ class CompareFTKEvents{
 							      {"z0",{100,-50,50}},
 							      {"chi2",{100,0,50}},
 							      {"ETA_PHI",{100,-2.5,2.5,100,-3.2,3.2}}};
+    std::map<std::string, std::string>  m_param_units={{"pt"," [MeV]"},
+                                                              {"eta",""},
+							      {"phi",""},
+							      {"d0"," [mm]"},
+							      {"z0"," [mm]"},
+							      {"chi2",""},
+							      {"ETA_PHI",""}};
     std::vector<std::string> m_variable_list={"pt","eta","phi","d0","z0","chi2","ETA_PHI"};    
+    static const std::string             m_name;
   };
 #endif //FTKSTANDALONEMONITORING_COMPAREFTKEVENTS_H
+
diff --git a/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKTracks.h b/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKTracks.h
index 243a7a45d7e0..32235c7c3fd1 100644
--- a/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKTracks.h
+++ b/Trigger/TrigFTK/FTKStandaloneMonitoring/FTKStandaloneMonitoring/CompareFTKTracks.h
@@ -1,8 +1,33 @@
 /*
 Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 */
-#ifndef FTKSTANDALONEMONITORING_COMPAREFTKTRACKS_H
-#define FTKSTANDALONEMONITORING_COMPAREFTKTRACKS_H
+
+///////////////////////////////////////////////////////////////////
+///
+/// This class aims to do track matching given two vectors of 
+/// FTK_RawTrack: one is the reference and one is the test
+/// this class gets also maps of histograms to be filled with
+/// the track parameters.
+/// The goal is to have a summary of the matching into four types of histos:
+/// HWSW*: if HW and SW tracks are completely matched, i.e. have the same track parameters within 0.1% of relative error
+///	      the distrubutions of the track paramters (like pt, eta, ...) are displayed in the histograms
+/// HWonly*: if HW tracks do not have SW tracks within m_dmax=0.2, 
+///		the distrubutions of these HW track paramters (like pt, eta, ...) are displayed in the histograms
+/// SWonly*: if SW tracks do not have HW tracks within m_dmax=0.2, 
+///		the distrubutions of these SW track paramters (like pt, eta, ...) are displayed in the histograms
+/// HWvsSW: if HW and SW tracks are not completely matched, 
+///		i.e. they are geometrically closed but do not have the same track parameters
+///		these histograms in turn are divided into :
+///		HWvsSWsw*: the distrubutions of the SW track paramters (like pt, eta, ...) are displayed in the histograms
+///		HWvsSWhw*: the distrubutions of the HW track paramters (like pt, eta, ...) are displayed in the histograms
+///		HWvsSWdiff*: the distrubutions of the difference btw the HW and SW track paramters (like pt, eta, ...) 
+///			     are displayed in the histograms
+/// 
+///////////////////////////////////////////////////////////////////
+
+
+#ifndef __CompareFTKTracks__
+#define __CompareFTKTracks__
 
 
 #include <iostream>
@@ -20,12 +45,26 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 class CompareFTKTracks{
   public:
     CompareFTKTracks();
+    
+    /// initialization of the object with the vectors of reference and test FTK_RawTrack, and the maps of histos to be filled
     CompareFTKTracks(std::vector<const FTK_RawTrack *> &ref, std::vector<const FTK_RawTrack *> &test, std::map<std::string , TH1D * > &map_histo, std::map<std::string , TH2D * > &map_histo_2D);
+    
+    /// here the matching is done: the criterium is angular distance specified by m_dmax
     void AssociateTracks();
+    
+    /// change the maximum distance between two tracks for angular matching: default 0.2
     void SetDRmax(double dmax){m_dmax=dmax;}
+    
+    /// here a rough printout equivalence between the two vectors of tracks is performed
     void TestEquivalence();
+
+    /// here histograms are filled wrt to the 4 types of histograms:
     void FillHistos();
+
+    /// functions which from a string concerning the track parameter returns the value of the track parameter, 
+    /// through the FTK_RawTrack method 
     double GetValue(std::string & variable, const FTK_RawTrack * tmptrk);
+
   private:
     std::map<std::string , TH1D * > m_map_histo;
     std::map<std::string , TH2D * > m_map_histo_2D;
@@ -36,4 +75,4 @@ class CompareFTKTracks{
     bool m_allmatched=true;
     std::vector<std::string> m_variable_list={"pt","eta","phi","d0","z0","chi2","ETA_PHI"};
 };
-#endif //FTKSTANDALONEMONITORING_COMPAREFTKTRACKS_H
+#endif //__CompareFTKTracks__
diff --git a/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKEvents.cxx b/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKEvents.cxx
index f906dbc53d41..f34365049fb7 100644
--- a/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKEvents.cxx
+++ b/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKEvents.cxx
@@ -4,219 +4,273 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 #include "FTKStandaloneMonitoring/CompareFTKEvents.h"
 #include <iostream>
 #include <string>
+#include "oh/OHRootProvider.h"
+#include "oh/OHRootReceiver.h"
+#include "oh/OHIterator.h"
+#include "oh/OHProviderIterator.h"
+#include "oh/OHServerIterator.h"
+#include "ipc/partition.h"
+#include "ipc/core.h"
+
+#include "TFile.h"
+#include "TTree.h"
+#include "TString.h"
+
+// ________________________________________________________________ //
+const std::string CompareFTKEvents::m_name = "HLmon_HWSWcomp";
+
+
+// ________________________________________________________________ //
 CompareFTKEvents::CompareFTKEvents()
 {
-    std::cout<<"Empty constructor"<<std::endl;
+    std::cout<<"Empty constructor. Please call: CompareFTKEvents(BSfile, NTUP_FTK_file)."<<std::endl;
 }
-CompareFTKEvents::CompareFTKEvents(const std::string &BSfile, const std::string &NTUP_FTK_file):
-   m_BSfile(BSfile),
-   m_NTUP_FTK_file(NTUP_FTK_file)
+
+
+// ________________________________________________________________ //
+CompareFTKEvents::CompareFTKEvents(const std::string& BSfile, const std::string& NTUP_FTK_file)
 {
-    std::cout<<"Input files constructor"<<std::endl;
-    std::cout<<m_BSfile<<std::endl;
-    std::cout<<m_NTUP_FTK_file<<std::endl;
-    m_myBSfile.open(m_BSfile.c_str(),std::ios::in | std::ios::binary);
-    if (m_myBSfile.fail()){
-        std::cout << "ERROR! cannot open file "<<m_BSfile.c_str();
-	m_myBSfile.clear( );
-    }
-}    
-// defining histograms
+    std::cout<<"CompareFTKEvents::CompareFTKEvents(). Reading files."<<std::endl;
+    // --- reading files and getting event numbers
+    read_BSfile(BSfile);
+    // reading NTUP_FTK file
+    readNTUP_FTKfile(NTUP_FTK_file);
+}
+
+
+// ________________________________________________________________ //
+
 void CompareFTKEvents::SetHistos(std::vector<std::string> histo_list){
     m_histo_list=histo_list;
     for (auto & istr : m_histo_list){
 	std::size_t pos = istr.find("_");      
         std::string str3 = istr.substr (pos+1);
         std::stringstream ss;
-        if (istr.find("HWSW")!=std::string::npos)        ss<<"HW=SIM;"<<str3<<";FTK HW=SIM Tracks";
-        else if (istr.find("HWonly")!=std::string::npos) ss<<"HW only;"<<str3<<";FTK HW Tracks w/o SW match";
-        else if (istr.find("SWonly")!=std::string::npos) ss<<"SW only;"<<str3<<";FTK SW Tracks w/o HW match";
-        else if (istr.find("HWvsSWhw")!=std::string::npos) ss<<"Matched Tracks but HW!=SW; HW "<<str3<<";FTK HW Tracks w/ SW match "<<str3;
-        else if (istr.find("HWvsSWsw")!=std::string::npos) ss<<"Matched Tracks but HW!=SW; SW "<<str3<<";FTK SW Tracks w/ HW match "<<str3;
+        
+	// definition of the titles and axis labels of 1D histograms published on OH
+	if (istr.find("HWSW")!=std::string::npos)        ss<<"HW=SIM;"<<str3<<m_param_units[str3]<<";FTK HW=SIM Tracks";
+        else if (istr.find("HWonly")!=std::string::npos) ss<<"HW only;"<<str3<<m_param_units[str3]<<";FTK HW Tracks w/o SW match";
+        else if (istr.find("SWonly")!=std::string::npos) ss<<"SW only;"<<str3<<m_param_units[str3]<<";FTK SW Tracks w/o HW match";
+        else if (istr.find("HWvsSWhw")!=std::string::npos) ss<<"Matched Tracks but HW!=SW; HW "<<str3<<m_param_units[str3]<<";FTK HW Tracks w/ SW match "<<str3;
+        else if (istr.find("HWvsSWsw")!=std::string::npos) ss<<"Matched Tracks but HW!=SW; SW "<<str3<<m_param_units[str3]<<";FTK SW Tracks w/ HW match "<<str3;
 	//else if (istr.find("res")!=std::string::npos)  ss<<"Matched Tracks but HW!=SW, #Delta  (SW-HW)/ HW;"<<str3<<";FTK HW Tracks w/ SW match";
 	else if (istr.find("nTrk")!=std::string::npos) ss<<istr<<";N tracks;Events";
 	std::string title = ss.str();
-	//if histo is not eta vs phi 2D histo
+	
+	//1D histograms
+	//if histo is NOT eta vs phi 2D histo these histos are published on OH
         if (istr.find("ETA_PHI")==std::string::npos){
             if (istr.find("nTrk")!=std::string::npos) m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),title.c_str(),100,0,100)));
  	    else if (istr.find("HWSW")!=std::string::npos|| istr.find("HWonly")!=std::string::npos||istr.find("SWonly")!=std::string::npos||(istr.find("HWvsSW")!=std::string::npos&&istr.find("diff")==std::string::npos))
 	       m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),title.c_str(),m_histo_param[str3].at(0),m_histo_param[str3].at(1),m_histo_param[str3].at(2))));
             else if (istr.find("HWvsSWdiff_pt")!=std::string::npos)
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta p_{T} (test-ref); p_{T}^{test} - p_{T}^{ref} ;FTK Tracks",1000,-5000,5000)));
+	       m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta p_{T} (test-ref); p_{T}^{test} - p_{T}^{ref} [MeV];FTK Tracks",1000,-5000,5000);
             else if (istr.find("HWvsSWdiff_eta")!=std::string::npos)
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta #eta (test-ref); #eta^{test} - #eta^{ref} ;FTK Tracks",2000,-0.1,0.1)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta #eta (test-ref); #eta^{test} - #eta^{ref} ;FTK Tracks",2000,-0.1,0.1);
             else if (istr.find("HWvsSWdiff_phi")!=std::string::npos)
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta #phi (test-ref); #phi^{test} - #phi^{ref} ;FTK Tracks",2000,-0.1,0.1)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta #phi (test-ref); #phi^{test} - #phi^{ref} ;FTK Tracks",2000,-0.1,0.1);
             else if (istr.find("HWvsSWdiff_d0")!=std::string::npos) 
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta d_{0} (test-ref); d_{0}^{test} - d_{0}^{ref} ;FTK Tracks",4000,-5.,5.)));
+	       m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta d_{0} (test-ref); d_{0}^{test} - d_{0}^{ref} [mm];FTK Tracks",4000,-5.,5.);
             else if (istr.find("HWvsSWdiff_z0")!=std::string::npos) 
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta z_{0} (test-ref); z_{0}^{test} - z_{0}^{ref} ;FTK Tracks",4000,-2.,2.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta z_{0} (test-ref); z_{0}^{test} - z_{0}^{ref} [mm];FTK Tracks",4000,-2.,2.);
             else if (istr.find("HWvsSWdiff_chi2")!=std::string::npos) 
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta chi2 (test-ref); chi2^{test} - chi2^{ref} ;FTK Tracks",4000,-5.,5.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta chi2 (test-ref); chi2^{test} - chi2^{ref} ;FTK Tracks",4000,-5.,5.);
             else if (istr.find("res_pt")!=std::string::npos)
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta p_{T} (test-ref)/ p_{T}^{ref};( p_{T}^{test} - p_{T}^{ref} )/ p_{T}^{ref};FTK Tracks",2000,-1.,1.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta p_{T} (test-ref)/ p_{T}^{ref};( p_{T}^{test} - p_{T}^{ref} )/ p_{T}^{ref};FTK Tracks",2000,-1.,1.);
             else if (istr.find("res_eta")!=std::string::npos)
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta #eta (test-ref)/ #eta^{ref};( #eta^{test} - #eta^{ref} )/ #eta^{ref};FTK Tracks",2000,-1.,1.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta #eta (test-ref)/ #eta^{ref};( #eta^{test} - #eta^{ref} )/ #eta^{ref};FTK Tracks",2000,-1.,1.);
             else if (istr.find("res_phi")!=std::string::npos)
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta #phi (test-ref)/ #phi^{ref};( #phi^{test} - #phi^{ref} )/ #phi^{ref};FTK Tracks",2000,-1.,1.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta #phi (test-ref)/ #phi^{ref};( #phi^{test} - #phi^{ref} )/ #phi^{ref};FTK Tracks",2000,-1.,1.);
             else if (istr.find("res_d0")!=std::string::npos) 
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta d_{0} (test-ref)/ d_{0}^{ref};( d_{0}^{test} - d_{0}^{ref} )/ d_{0}^{ref};FTK Tracks",4000,-2.,2.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta d_{0} (test-ref)/ d_{0}^{ref};( d_{0}^{test} - d_{0}^{ref} )/ d_{0}^{ref};FTK Tracks",4000,-2.,2.);
             else if (istr.find("res_z0")!=std::string::npos) 
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta z_{0} (test-ref)/ z_{0}^{ref};( z_{0}^{test} - z_{0}^{ref} )/ z_{0}^{ref};FTK Tracks",4000,-2.,2.)));
+		m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta z_{0} (test-ref)/ z_{0}^{ref};( z_{0}^{test} - z_{0}^{ref} )/ z_{0}^{ref};FTK Tracks",4000,-2.,2.);
             else if (istr.find("res_chi2")!=std::string::npos) 
-		m_map_histo.insert(std::map<std::string, TH1D *>::value_type(istr, new TH1D(istr.c_str(),"#Delta chi2 (test-ref)/ chi2^{ref};( chi2^{test} - chi2^{ref} )/ chi2^{ref};FTK Tracks",4000,-2.,2.)));
+	       m_map_histo[istr] = new TH1D(istr.c_str(),"#Delta chi2 (test-ref)/ chi2^{ref};( chi2^{test} - chi2^{ref} )/ chi2^{ref};FTK Tracks",4000,-2.,2.);
 	}
+	
+	// 2D histograms containing ETA_PHI in the histo name are not published on OH
 	else {
  	    m_map_histo_2D.insert(std::map<std::string, TH2D *>::value_type(istr, new TH2D(istr.c_str(),title.c_str(),100,-2.5,2.5,100,-3.2,3.2)));	
 	}
     }	
 }
-// reading BS file, starting loop on events and writing histograms
-void CompareFTKEvents::Execute()
+
+
+// ________________________________________________________________ //
+bool CompareFTKEvents::readNTUP_FTKfile(const std::string& NTUP_FTK_file)
 {
-    m_Nevents_BS=GetNEventsBS();
-    std::cout<<"Input BS file has N events: "<<m_Nevents_BS<<std::endl;
-    readNTUP_FTKfile();
-    if (m_Nevents_BS!=m_Nevents_NTUPFTK) {
-	std::cout<<"different number of events: "<<m_Nevents_BS<<" "<<m_Nevents_NTUPFTK<<std::endl;
-	m_allmatched=false;
+   //! Reading FTK file
+   //! Reading number of events, setting branches, ttrees for further reading
+   //! returning true when successful, otherwise false
+
+    // --- open file
+   std::cout<<"\nCompareFTKEvents::readNTUP_FTKfile()"<<std::endl; 
+   std::cout<<"Reading NTUP_FTK file: "<<NTUP_FTK_file<<std::endl;
+    m_fntupftk = TFile::Open(NTUP_FTK_file.c_str(),"READ");
+    if (!m_fntupftk) {
+       std::cout<<"ERROR!! NTUP_FTK file could not be opened: "<<NTUP_FTK_file<<std::endl;
+       exit(3);
+       return false;
+    }
+
+    // --- reading tree evtinfo
+    static const TString str_tree_evtinfo = "evtinfo";
+    m_tevtinfo = (TTree*)m_fntupftk->Get(str_tree_evtinfo);
+    if ( !m_tevtinfo ) {
+       std::cout<<"ERROR!! NTUP_FTK file does not contain tree: "<<str_tree_evtinfo<<std::endl;
+       return false;
     }
-    EventLoop();
-    WriteHistos();
-}
-// reading the SW NTUP_FTK TTrees
-void CompareFTKEvents::readNTUP_FTKfile()
-{
-    std::cout<<"Reading NTUP_FTK file "<<m_NTUP_FTK_file<<std::endl;
-    m_fntupftk = new TFile(m_NTUP_FTK_file.c_str());
-    if (!m_fntupftk) std::cout<<"ERROR!! NTUP_FTK file could not be opened: "<<m_NTUP_FTK_file.c_str()<<std::endl;
-    if (!m_fntupftk->GetListOfKeys()->Contains(m_str_tree_evtinfo.c_str())) std::cout<<"ERROR!! NTUP_FTK file does not contain tree: "<<m_str_tree_evtinfo.c_str()<<std::endl;
-    m_tevtinfo = (TTree*)m_fntupftk->Get(m_str_tree_evtinfo.c_str());
     m_tevtinfo->SetBranchAddress("RunNumber",&m_RN);  
     m_tevtinfo->SetBranchAddress("EventNumber",&m_EN);  
     m_tevtinfo->SetBranchAddress("LB",&m_LB);  
     m_tevtinfo->SetBranchAddress("BCID",&m_BCID);  
     m_tevtinfo->SetBranchAddress("ExtendedLevel1ID",&m_EL1ID);  
     m_tevtinfo->SetBranchAddress("Level1TriggerType",&m_l1TT); 
-    if (!m_fntupftk->GetListOfKeys()->Contains(m_str_tree_ftkdata.c_str())) std::cout<<"ERROR!! NTUP_FTK file does not contain tree: "<<m_str_tree_ftkdata.c_str()<<std::endl;
-    m_theTree=(TTree *)m_fntupftk->Get(m_str_tree_ftkdata.c_str());
-    m_ft=new FTKTrackStream();
-    if (!m_theTree->GetListOfBranches()->Contains(m_str_tree_ftkstream.c_str()))std::cout<<"ERROR!! NTUP_FTK file does not contain branch: "<<m_str_tree_ftkstream.c_str()<<std::endl;
-    auto branch  = m_theTree->GetBranch(m_str_tree_ftkstream.c_str());
+
+    // --- reading tree ftkdata
+    static const TString str_tree_ftkdata = "ftkdata";
+    m_theTree=(TTree*)m_fntupftk->Get(str_tree_ftkdata);
+    if ( !m_theTree ) {
+       std::cout<<"ERROR!! NTUP_FTK file does not contain tree: "<<str_tree_ftkdata<<std::endl;
+       return false;
+    }
+    static const TString str_tree_ftkstream = "FTKMergedTracksStream";
+    TBranch*  branch  = m_theTree->GetBranch(str_tree_ftkstream);
+    if ( !branch ) {
+       std::cout<<"ERROR!! NTUP_FTK file does not contain branch: "<<str_tree_ftkstream<<std::endl;                                                        return false;
+    }
+    m_ft = new FTKTrackStream();
     branch->SetAddress(&m_ft);
-    m_Nevents_NTUPFTK=m_theTree->GetEntries();
+    
+    // --- setting number of events
+    //m_Nevents_NTUPFTK = m_theTree->GetEntries();
+    std::cout<<"Info. Input FTK file has "<<m_theTree->GetEntries()<<" events."<<std::endl;
+    return true;
 }
-// decoding functions from FTKByteStreamDecoderEncoder
-StatusCode CompareFTKEvents::decode(uint32_t nTracks, OFFLINE_FRAGMENTS_NAMESPACE::PointerType rodData, FTK_RawTrackContainer* result) {
 
+
+// ________________________________________________________________ //
+void CompareFTKEvents::decode(uint32_t nTracks, OFFLINE_FRAGMENTS_NAMESPACE::PointerType rodData, FTK_RawTrackContainer* result) {
+  
   result->reserve(result->size() + nTracks);
   for ( size_t i = 0; i < nTracks; ++i ) {
     FTK_RawTrack* track = unpackFTTrack( rodData );
-    rodData += TRACKBLOBSIZE;
+    rodData += m_TrackBlobSize;
     result->push_back(track);
   }
-  return StatusCode::SUCCESS;
 }
+
+
+// ________________________________________________________________ //
 FTK_RawTrack* CompareFTKEvents::unpackFTTrack( OFFLINE_FRAGMENTS_NAMESPACE::PointerType data) {  
   FTK_RawTrack* track = new FTK_RawTrack(data[0], data[1], data[2], data[3], data[4], data[5]); // first six words are track params
-  data += TRACKPARAMSBLOBSIZE;
+  data += m_TrackParamsBlobSize;
 
   // get pixel hits  
-  track->getPixelClusters().resize(NPIXLAYERS);
-  for ( size_t i = 0; i < size_t(NPIXLAYERS); ++i) {
-    size_t offset = PIXHITPARAMSBLOBSIZE*i;
+  track->getPixelClusters().resize(m_NPixLayers);
+  for ( size_t i = 0; i < size_t(m_NPixLayers); ++i) {
+    size_t offset = m_PixHitParamsBlobSize*i;
     unpackPixCluster(data+offset, track->getPixelCluster(i) );    
   }
-  data += PIXHITPARAMSBLOBSIZE*NPIXLAYERS;
+  data += m_PixHitParamsBlobSize*m_NPixLayers;
 
   // gets SCT hits
-  track->getSCTClusters().resize(NSCTLAYERS);
-  for ( size_t i = 0; i < size_t(NSCTLAYERS); ++i) {
-    size_t offset = SCTHITPARAMSBLOBSIZE*i;
+  track->getSCTClusters().resize(m_NSCTLayers);
+  for ( size_t i = 0; i < size_t(m_NSCTLayers); ++i) {
+    size_t offset = m_SCTHitParamsBlobSize*i;
     unpackSCTCluster(data+offset, track->getSCTCluster(i) );    
   }
   // no more shifts needed
   return track;
 }  
+// ________________________________________________________________ //
+
 void CompareFTKEvents::unpackPixCluster(OFFLINE_FRAGMENTS_NAMESPACE::PointerType data, FTK_RawPixelCluster& cluster) {
   cluster.setWordA(*data);
   cluster.setWordB(*(data+1));
 }
-// Looping over events of the HW (BS_FTK) and SW (NTUP_FTK files) and collecting track info
-void CompareFTKEvents::EventLoop()
+
+// ________________________________________________________________ //
+void CompareFTKEvents::ExecuteEventLoop(int nevtmax)
 {
-    std::cout<<"Starting Loop"<<std::endl;
-    m_tmpbufpos=0;
-    if (m_nevtmax==0)m_nevtmax=std::min(m_Nevents_BS,m_Nevents_NTUPFTK);
-    for (int ievent=1;ievent<=m_nevtmax;ievent++){
-       m_tmpbufpos =readBSevent( 1,m_tmpbufpos);  
-       int lengthdata=m_data.size();
-       uint32_t * data32=NULL;
-       data32=new uint32_t[lengthdata]; 
-       for(int ij=0; ij<lengthdata; ij++) {
-           data32[ij]=m_data[ij];
-       }
-       OFFLINE_FRAGMENTS_NAMESPACE::PointerType pdata=data32;
+   //! Run over all events of BS and FTKSim file
+   //! nevtmax > 0: limit number of events
+   
+   std::cout<<"Running event loop"<<std::endl;
+   //! looping over events
+   int Nevents_NTUPFTK = m_theTree->GetEntries();
+   if (m_Nevents_BS!=Nevents_NTUPFTK) {
+      std::cout<<"Error! Different number of events: "<<m_Nevents_BS<<" (BS) and "<<Nevents_NTUPFTK<<" (FTKSim)"<<std::endl;
+      m_allmatched=false;
+      return;
+    }
+    nevtmax = ( nevtmax>0 ) ? std::min(nevtmax,Nevents_NTUPFTK) : Nevents_NTUPFTK;
+
+    // looping over the requested number of events 
+    std::streampos tmpbufpos=0;
+    for (int ievent=1 ; ievent<=nevtmax ; ievent++ ){
+       // --- BS file
+       std::vector<uint32_t> data;
+       tmpbufpos = readBSevent( 1,tmpbufpos, data);  
        //event info are given to FullEventFragment
-       eformat::read::FullEventFragment fe(pdata);
+       eformat::read::FullEventFragment fe(&data[0]);// OFFLINE_FRAGMENTS_NAMESPACE::PointerType p=&m_data[0];
+       if (m_verbose) std::cout<<"Run Number "<<fe.run_no()<<" Lvl1 "<<fe.lvl1_id()<<" BCID "<<fe.bc_id()<<std::endl;
        std::vector< eformat::read::ROBFragment > ROBFragments_v;
-       if (m_verbose)std::cout<<"Run Number "<<fe.run_no()<<" Lvl1 "<<fe.lvl1_id()<<" BCID "<<fe.bc_id()<<std::endl;
        fe.robs( ROBFragments_v );
-       FTK_RawTrackContainer* trkcontainer= new FTK_RawTrackContainer();
+
+       FTK_RawTrackContainer trkcontainerBS;
        std::vector<const FTK_RawTrack *> ftkBSref;
        int nrob=0;
        int nTrks=0;
+       // --- BS, run over all ROBFragments
        for(auto& ROBFragment : ROBFragments_v){
-           unsigned int niTrks=0;
            eformat::helper::SourceIdentifier ROBSource_id = eformat::helper::SourceIdentifier( ROBFragment.source_id() );
-           if(ROBSource_id.subdetector_id() != eformat::TDAQ_FTK ){
-              continue;
-           }
-           const uint32_t *rod_data = ROBFragment.rod_data();
+           if(ROBSource_id.subdetector_id() != eformat::TDAQ_FTK )  continue;
+           const uint32_t* rod_data = ROBFragment.rod_data();
            uint32_t rod_ndata = ROBFragment.rod_ndata();
-	   if( ( rod_ndata - m_trackBlockOffsetStart - m_trackBlockOffsetEnd ) % TRACKBLOBSIZE != 0 ){
+	   if( ( rod_ndata - m_trackBlockOffsetStart - m_trackBlockOffsetEnd ) % m_TrackBlobSize != 0 ){
 	      std::cout<<"Error: wrong size of rod"<<rod_ndata<<std::endl;
 	      continue;
 	   }
-           niTrks = ( rod_ndata - m_trackBlockOffsetStart - m_trackBlockOffsetEnd ) / TRACKBLOBSIZE;
+           unsigned int niTrks = ( rod_ndata - m_trackBlockOffsetStart - m_trackBlockOffsetEnd ) / m_TrackBlobSize;
 	   nTrks+=niTrks;
            rod_data += m_trackBlockOffsetStart;            // moving data pointer to first track block
-	   if (m_verbose){
-	      std::cout<<"test of working rod l1 "<<ROBFragment.rod_lvl1_id()<<" ndata "<<rod_ndata<<std::endl;
-	   }
+	   if (m_verbose) std::cout<<"test of working rod l1 "<<ROBFragment.rod_lvl1_id()<<" ndata "<<rod_ndata<<std::endl;
+
 	   // decoding the rod info into FTK track container
-           StatusCode sc;
-	   sc=decode(niTrks,rod_data, trkcontainer);
-	   if (!sc.isSuccess()) std::cout<<"ERROR!! decode function did not return success"<<std::endl;
-	   if (trkcontainer->size()==0) {
+           decode(niTrks,rod_data, &trkcontainerBS);
+	   if ( trkcontainerBS.size() == 0 ) {
                std::cout<<"no FTK tracks from BS file continue"<<std::endl;
 	       continue;
 	   }
-	   if (m_verbose){
-	      std::cout<<sc.isSuccess()<<std::endl;
-              std::cout<< "collection of size " << trkcontainer->size() << std::endl;
-	   }
-           for ( unsigned int i = 0 ; i < niTrks; ++i ) {
-	       ftkBSref.push_back(trkcontainer->at(i));
-	   }
+	   if (m_verbose)  std::cout<< "collection of size " << trkcontainerBS.size() << std::endl;
+           for ( unsigned int i = 0 ; i < niTrks; ++i ) ftkBSref.push_back(trkcontainerBS.at(i));
 	   nrob+=1;	  
        }
+       // filling histograms with number of HW tracks per event
        auto search = m_map_histo.find("nTrk_HW");
        if(search != m_map_histo.end()) search->second->Fill(nTrks);
        else  std::cout << "Not found "<<search->first<<std::endl;
        if (nrob>1){std::cout<<"!!!!!!!!!!SOMETHING WRONG number of robs >1:"<<nrob<<std::endl;}
-       std::cout<<"Event "<<ievent<<" N tracks BS file "<<trkcontainer->size()<<std::endl;
+       std::cout<<"Event "<<ievent<<" N tracks BS file "<<trkcontainerBS.size()<<std::endl;
        // end reading info from BS file
        //---------------------------------------------------------------------//
-       // start reading info from NTUP_FTK file
+
+
+       //---------------------------------------------------------------------//
+       // --- start reading info from NTUP_FTK file
        m_theTree->GetEvent(ievent-1); 
-       FTK_RawTrackContainer* trkcontainerNTUP= new FTK_RawTrackContainer();
+       FTK_RawTrackContainer trkcontainerNTUP;
        std::vector<const FTK_RawTrack *> ftkNTUPtest;
-       int NTracksNTUP;
-       NTracksNTUP=m_ft->getNTracks();
+       int NTracksNTUP = m_ft->getNTracks();
+       // filling histograms with number of SW tracks per event
        auto search_SW = m_map_histo.find("nTrk_SW");
        if(search_SW != m_map_histo.end()) search_SW->second->Fill(NTracksNTUP);
        else  std::cout << "Not found "<<search_SW->first<<std::endl;
+       // to be able to match SW and HW tracks the same object class needs to be used:
+       // HW tracks are FTK_RawTrack; SW tracks are FTKTrack.
+       // needed a by-hand transformation of a FTKTrack object into a FTK_RawTrack object 
        for(int it=0; it<NTracksNTUP;it++){
          FTKTrack* ftktrk=m_ft->getTrack(it);
          FTK_RawTrack* rawftktrk=new FTK_RawTrack();
@@ -227,72 +281,219 @@ void CompareFTKEvents::EventLoop()
 	 rawftktrk->setInvPt(2*ftktrk->getHalfInvPt());
 	 rawftktrk->setChi2(ftktrk->getChi2());
 	 rawftktrk->setBarcode(ftktrk->getBarcode());
-	 trkcontainerNTUP->push_back(rawftktrk);
-         ftkNTUPtest.push_back(trkcontainerNTUP->at(it));
+	 trkcontainerNTUP.push_back(rawftktrk);
+         ftkNTUPtest.push_back(trkcontainerNTUP.at(it));
        }
-       std::cout<<"Event "<<ievent<<" N tracks NTUP_FTK "<<trkcontainerNTUP->size()<<std::endl;
+       std::cout<<"Event "<<ievent<<" N tracks NTUP_FTK "<<trkcontainerNTUP.size()<<std::endl;
        // end reading info from NTUP_FTK file
        //---------------------------------------------------------------------//
        // start comparing infos
        m_tevtinfo->GetEntry(ievent-1);
-       if (NTracksNTUP!=nTrks){std::cout<<"different N tracks: "<<NTracksNTUP<<" "<<nTrks<<std::endl;m_allmatched=false;}
-       if (fe.run_no()!=(unsigned int)m_RN){std::cout<<"different RunNUmber: "<<fe.run_no()<<" "<<m_RN<<std::endl; m_allmatched=false;}
-       if (fe.bc_id()!=(unsigned int)m_BCID){std::cout<<"different BCID: "<<fe.bc_id()<<" "<<m_BCID<<std::endl;m_allmatched=false;}
+       if ( NTracksNTUP != nTrks ){
+	  std::cout<<"Error! different N tracks. FTKSim:"<<NTracksNTUP<<"\t BS: "<<nTrks<<std::endl;
+	  m_allmatched=false;
+       }
+       if ( fe.run_no()!=(unsigned int)m_RN ) {
+	  std::cout<<"Error! different RunNumber: "<<fe.run_no()<<" "<<m_RN<<std::endl; 
+	  m_allmatched=false;
+       }
+       if ( fe.bc_id()!=(unsigned int)m_BCID ) {
+	  std::cout<<"Error! different BCID: "<<fe.bc_id()<<" "<<m_BCID<<std::endl;
+	  m_allmatched=false;
+       }
        // end comparing infos
        //---------------------------------------------------------------------//
-       // start matching
+       // quick manual check of the parameters of SW and HW tracks before doing the real matching
+       // if the two files BS anf NTUP_FTK contained exactly the same information, 
+       // there should be no difference in the track parameters
        for ( int i = 0 ; i < std::min((int) nTrks,NTracksNTUP); ++i ) {
-           if(trkcontainerNTUP->at(i)->getD0()!=0&&trkcontainerNTUP->at(i)->getZ0()!=0&&trkcontainerNTUP->at(i)->getInvPt()!=0&&
-	      trkcontainerNTUP->at(i)->getPhi()!=0&&trkcontainerNTUP->at(i)->getCotTh()!=0&&trkcontainerNTUP->at(i)->getChi2()!=0
-	      &&(
-	       fabs(trkcontainer->at(i)->getD0()/trkcontainerNTUP->at(i)->getD0()-1.)>0.001||
-               fabs(trkcontainer->at(i)->getZ0()/trkcontainerNTUP->at(i)->getZ0()-1.)>0.001||
-               fabs(trkcontainer->at(i)->getInvPt()/trkcontainerNTUP->at(i)->getInvPt()-1.)>0.001||
-               fabs(trkcontainer->at(i)->getPhi()/trkcontainerNTUP->at(i)->getPhi()-1.)>0.001||
-               fabs(trkcontainer->at(i)->getCotTh()/trkcontainerNTUP->at(i)->getCotTh()-1.)>0.001||
-               fabs(trkcontainer->at(i)->getChi2()/trkcontainerNTUP->at(i)->getChi2()-1.)>0.001)){
-		   if (m_verbose){
+           if(trkcontainerNTUP.at(i)->getD0()!=0&&trkcontainerNTUP.at(i)->getZ0()!=0&&trkcontainerNTUP.at(i)->getInvPt()!=0&&
+	      trkcontainerNTUP.at(i)->getPhi()!=0&&trkcontainerNTUP.at(i)->getCotTh()!=0&&trkcontainerNTUP.at(i)->getChi2()!=0 && 
+	      ( fabs(trkcontainerBS.at(i)->getD0()/trkcontainerNTUP.at(i)->getD0()-1.)>0.001||
+		fabs(trkcontainerBS.at(i)->getZ0()/trkcontainerNTUP.at(i)->getZ0()-1.)>0.001||
+		fabs(trkcontainerBS.at(i)->getInvPt()/trkcontainerNTUP.at(i)->getInvPt()-1.)>0.001||
+		fabs(trkcontainerBS.at(i)->getPhi()/trkcontainerNTUP.at(i)->getPhi()-1.)>0.001||
+		fabs(trkcontainerBS.at(i)->getCotTh()/trkcontainerNTUP.at(i)->getCotTh()-1.)>0.001||
+		fabs(trkcontainerBS.at(i)->getChi2()/trkcontainerNTUP.at(i)->getChi2()-1.)>0.001) ) {
+	      m_allmatched=false;
+	      if (m_verbose) {
 		       std::cout<<"Difference in comparing trk "<<i<<std::endl;
-		       std::cout<<"\td0 : \t"<<trkcontainer->at(i)->getD0()<<"\t"<<trkcontainerNTUP->at(i)->getD0()<<std::endl;
-		       std::cout<<"\tz0 : \t"<<trkcontainer->at(i)->getZ0()<<"\t"<<trkcontainerNTUP->at(i)->getZ0()<<std::endl;
-		       std::cout<<"\tipt : \t"<<trkcontainer->at(i)->getInvPt()<<"\t"<<trkcontainerNTUP->at(i)->getInvPt()<<std::endl;
-		       std::cout<<"\tPhi : \t"<<trkcontainer->at(i)->getPhi()<<"\t"<<trkcontainerNTUP->at(i)->getPhi()<<std::endl;
-		       std::cout<<"\tCotTh : \t"<<trkcontainer->at(i)->getCotTh()<<"\t"<<trkcontainerNTUP->at(i)->getCotTh()<<std::endl;
-		       std::cout<<"\tChi2 : \t"<<trkcontainer->at(i)->getChi2()<<"\t"<<trkcontainerNTUP->at(i)->getChi2()<<std::endl;
-		   }    
-		   m_allmatched=false;
-               }
-	   else {if (i%std::min(nTrks,NTracksNTUP)==0 && m_allmatched){std::cout<<"Track Parameters btw BS_FTK and NTUP_FTK are the same: good!"<<std::endl;}}
+		       std::cout<<"\td0 : \t"<<trkcontainerBS.at(i)->getD0()<<"\t"<<trkcontainerNTUP.at(i)->getD0()<<std::endl;
+		       std::cout<<"\tz0 : \t"<<trkcontainerBS.at(i)->getZ0()<<"\t"<<trkcontainerNTUP.at(i)->getZ0()<<std::endl;
+		       std::cout<<"\tipt : \t"<<trkcontainerBS.at(i)->getInvPt()<<"\t"<<trkcontainerNTUP.at(i)->getInvPt()<<std::endl;
+		       std::cout<<"\tPhi : \t"<<trkcontainerBS.at(i)->getPhi()<<"\t"<<trkcontainerNTUP.at(i)->getPhi()<<std::endl;
+		       std::cout<<"\tCotTh : \t"<<trkcontainerBS.at(i)->getCotTh()<<"\t"<<trkcontainerNTUP.at(i)->getCotTh()<<std::endl;
+		       std::cout<<"\tChi2 : \t"<<trkcontainerBS.at(i)->getChi2()<<"\t"<<trkcontainerNTUP.at(i)->getChi2()<<std::endl;
+	      }    
+	   }
+	   else {
+	      if ( i%std::min(nTrks,NTracksNTUP)==0 && m_allmatched ) {
+		 std::cout<<"Track Parameters btw BS_FTK and NTUP_FTK are the same: good!"<<std::endl;
+	      }
+	   }
        }
+       //---------------------------------------------------------------------//
+       // start matching
        m_compTrk= new CompareFTKTracks(ftkBSref,ftkNTUPtest, m_map_histo, m_map_histo_2D);
        m_compTrk->AssociateTracks();
        m_compTrk->FillHistos();
-       delete data32;
+       //---------------------------------------------------------------------//
      }
 }
-void CompareFTKEvents::WriteHistos(){
-    m_fout= new TFile("./out.histo.root","RECREATE");
-    m_fout->cd();
-    for(auto & imap : m_map_histo){
-        imap.second->Write();
-    }
-    for(auto & imap : m_map_histo_2D){
-        imap.second->Write();
-    }
-    m_fout->Write();
-    m_fout->Close();
-    std::cout<<"Histo written into file "<<m_fout->GetName()<<std::endl;
+
+
+// ________________________________________________________________ //
+std::unique_ptr<const IPCPartition*> CompareFTKEvents::GetIPCPartition(const std::string& partition_name) 
+{   
+   //!  partition_name must be: 'online', "", or <partition_name>
+   //! Returns always a valid IPCPartition ptr.
+   
+   const IPCPartition* ipcpartition = nullptr; // return value
+
+   // initialization of IPCParition
+   if ( partition_name=="" || partition_name=="online" ) {
+      try {
+	 ipcpartition      = &daq::rc::OnlineServices::instance().getIPCPartition();
+	 std::cout<<"==> Using partition from Online Service Instance with name "<<ipcpartition->name()
+		  <<". You are running in a partition"<<std::endl;
+      }
+      catch ( daq::rc::Exception & ex ){	    
+	 ers::warning(ex);  //or throw e; 
+	 std::cout<<"CompareFTKEvents. Unable to retrieve IPCPartition from daq::rc::OnlineServiced."<<std::endl; //...
+      }
+      //if ( partition_name == "online" || ipcpartition )  return ipcpartition;
+      if ( ipcpartition ) {
+	 std::unique_ptr<const IPCPartition*> ret = std::make_unique<const IPCPartition*>(ipcpartition);
+	 ret.release();
+	 return ret;
+      }
+   }
+
+   if ( !ipcpartition ) {
+      if ( partition_name != "" ) {
+	 std::cout<<"Instantiatinng new IPCPartition with name specified through input argument: "<<partition_name<<std::endl;
+	 ipcpartition = new IPCPartition( partition_name );
+      }
+      else if ( std::getenv("TDAQ_PARTITION") && std::string(std::getenv("TDAQ_PARTITION"))!="" ) {
+	 ipcpartition = new IPCPartition( std::getenv("TDAQ_PARTITION") );
+	 std::cout<<"Using partition name set by environment variable TDAQ_PARTITION: "<<std::getenv("TDAQ_PARTITION")<<std::endl;
+      }
+      else {
+	 ipcpartition = new IPCPartition( "ATLAS" );
+	 std::cout<< "Using default partition name: "<<ipcpartition->name()<<std::endl;
+	 std::cout<< "Please provide it with \"-p [partition_name]\" or with env variable TDAQ_PARTITION"<<std::endl;
+      }
+   }
+   //   return std::unique_ptr<const IPCPartition*>(ipcpartition);
+   return std::make_unique<const IPCPartition*>(ipcpartition);
+}
+
+
+// ________________________________________________________________ //
+void CompareFTKEvents::PublishHistosToPartition(const std::string& partition_name) {
+   //! Publish histograms to (online) partition [OH].
+   //! Default, when no string is provided:
+   //!     Try to access 'online' partition. Otherwise use env variable 
+   //!     TDAQ_PARTITION, or use default partition-name "ATLAS".
+   //! 
+   
+   
+   // --- Publish histograms to OH
+   auto ipcpartition = GetIPCPartition(partition_name);
+   if ( !ipcpartition.get() ) {
+      std::cout<<"PublishHistosToPartition. No partition initiated. Cannot publish to online service."<<std::endl;
+      return;
+   }
+
+   //initialization of the OH provider
+   const std::string OHServer("Histogramming"); 
+   const std::string OHName("FTK_" + m_name);   
+   const std::string OHCumulName("FTK_" + m_name + "_Cumulative");   
+
+   try {
+      OHRootProvider ohProvider ( **ipcpartition , OHServer, OHName ); // try...catch..
+      OHRootProvider ohProvCumu ( **ipcpartition , OHServer, OHCumulName ); // try...catch..
+      std::cout<<"OK! Publishing to OH. Server: "<<OHServer<<"\t providers: "<<OHName<<", "<<OHCumulName<<std::endl;
+      ERS_LOG("OH: publishing in " << OHServer << "." << m_name );
+       
+      for(auto & imap : m_map_histo)  {
+	 TH1D* histo = imap.second;
+	 TH1D sumhist(*histo);
+
+	 try {
+	    OHRootHistogram ohh = OHRootReceiver::getRootHistogram( **ipcpartition , OHServer, OHCumulName, histo->GetName());
+	    TH1D* oh1 = (TH1D*)ohh.getObject().get();
+	    std::cout<<"Histogram found with "<<oh1->GetEntries()<<" entries."<<std::endl;
+	    sumhist.Add(oh1);
+	 }
+	 catch ( daq::oh::Exception& ex) { 
+	    std::cout<<"No initial cumulative histogram found for histo: "<<histo->GetName()<<std::endl;
+	    //ers::warning(ex);
+	 }
+      
+	 // --- list valid histograms
+	 // try {
+	 // 	 std::cout<<" --- test : "<<std::endl;
+	 // 	 OHHistogramIterator hit2( *ipcpartition, OHServer, OHCumulName, ".*" );//OHIterator
+	 // 	 std::cout << " contains " << hit2.entries() << " " << "H" << "(s) *ipcpartition (4)." << std::endl;
+	 // 	 OHHistogramIterator hit3( *ipcpartition, OHServer, OHCumulName, histo->GetName()  );//OHIterator
+	 // 	 std::cout << " contains " << hit3.entries() << " " << "H" << "(s) *ipcpartition (4)." << std::endl;
+	 // }
+	 // catch( ers::Issue & ex ) {
+	 // 	 std::cout<<"test 'list valid histograms' failed"<<std::endl;
+	 // 	 ers::error( ex );
+	 // }
+
+	 // publish histograms ...
+	 try {
+	    ohProvCumu.OHRootProvider::publish( sumhist, sumhist.GetName(), -1 ); 
+	    ohProvider.OHRootProvider::publish( *((TH1D*)histo),  histo->GetName(), -1 );
+	    std::cout<<"Histograms published successfully ("<<histo->GetName()<<")."<<std::endl;
+	 }
+	 catch( ers::Issue & ex ) {
+	    std::cout<<"Something went wrong while publishing histograms."<<std::endl;
+	    ers::error( ex );
+	 }
+
+      }
+   }
+   catch ( daq::oh::Exception & ex) { // OHRootProvider constructor
+      std::cout<<"Warning. OH error exception. Cannot communicate with OH when using partition "<< (*ipcpartition)->name()<<std::endl;
+      std::cout<<"Printing warning message:"<<std::endl;
+      ers::warning(ex);  
+      std::cout<<"PublishHistosToPartition. Cannot publish to online service."<<std::endl;
+      return;
+   }  
+}
+
+
+// ________________________________________________________________ //
+void CompareFTKEvents::WriteHistosToFile(const std::string& filename){
+
+    // --- write histograms to file.
+    std::cout<<"CompareFTKEvents. Writing histos to file:     "<<filename<<std::endl;
+    TFile* fout= TFile::Open(filename.c_str(),"RECREATE");
+    fout->cd();
+    for(auto & imap : m_map_histo)    imap.second->Write();
+    for(auto & imap : m_map_histo_2D) imap.second->Write();
+    std::cout<<"CompareFTKEvents. Histograms written to file: "<<fout->GetName()<<std::endl;
+    fout->Close();
+    delete fout;
 }
-std::streampos CompareFTKEvents::readBSevent(int ievent,std::streampos startbufpos)
+
+
+// ________________________________________________________________ //
+std::streampos CompareFTKEvents::readBSevent(int ievent,std::streampos startbufpos, std::vector<uint32_t>& data)
 {
+   
     if (m_verbose) std::cout<<"Reading BS event"<<std::endl;
-    m_data.clear();
-    uint32_t word;
+    if (m_verbose) std::cout<<"pointer position start"<<m_myBSfile.tellg()<<std::endl;
+
+    data.clear();
     int iil=0;
     int nprocessedevents=0;
     std::streampos lastpos;
-    if (m_verbose) std::cout<<"pointer position start"<<m_myBSfile.tellg()<<std::endl;
-    if (ievent ==1){
+    if (ievent == 1 ){
        if (m_verbose) std::cout<<"going to buffer position "<<startbufpos<<std::endl;
        m_myBSfile.seekg(startbufpos);
     }
@@ -300,18 +501,18 @@ std::streampos CompareFTKEvents::readBSevent(int ievent,std::streampos startbufp
     while(m_myBSfile.is_open())
     {
        if(m_myBSfile.eof()){  break; }
-       word=0;
+       uint32_t word=0;
        m_myBSfile.read ((char*)&word, sizeof(word));
        if (word==m_checkword) {
 	  nprocessedevents+=1;
           if (m_verbose) std::cout<<"pointer position start event"<<m_myBSfile.tellg()<<std::endl;
        }
        if (nprocessedevents==ievent){ 
-          m_data.push_back(word);
+          data.push_back(word);
           iil++;
-	  lastpos=m_myBSfile.tellg();
+	  lastpos = m_myBSfile.tellg();
        }
-       else if (nprocessedevents>ievent) {
+       else if ( nprocessedevents > ievent ) {
           if (m_verbose) std::cout<<"pointer position end event "<<lastpos<<std::endl;
           break;
        }
@@ -319,34 +520,46 @@ std::streampos CompareFTKEvents::readBSevent(int ievent,std::streampos startbufp
     if (m_verbose) std::cout<<"pointer position before closing"<<m_myBSfile.tellg()<<std::endl;
     return lastpos;    
 }
-int CompareFTKEvents::GetNEventsBS()
+
+// ________________________________________________________________ //
+bool CompareFTKEvents::read_BSfile(const std::string& BSfile)
 {
-    std::cout<<"Getting N events BS file"<<std::endl;
-    uint32_t word;
-    int nevents=0;
-    while(m_myBSfile.is_open())
-    {
-       if(m_myBSfile.eof()){ break; }
-       word=0;
+   //! Opening BSfile for later reading.
+   //! Counting number of events (m_Nevents_BS) and checking consistency of all lines
+   //! return true when successful. Otherwise false.
+   
+   std::cout<<"\nCompareFTKEvents::read_BSfile()"<<std::endl;
+   std::cout<<"Getting number of events from BS file: "<<BSfile<<std::endl;
+    m_myBSfile.open(BSfile.c_str(),std::ios::in | std::ios::binary);
+    if (m_myBSfile.fail()){
+       std::cout << "ERROR! cannot open BS file: "<<BSfile.c_str()<<std::endl;
+       exit(3);
+       return false;
+    }
+
+    // --- count events
+    m_Nevents_BS = 0;
+    while ( m_myBSfile.is_open() ) {
+       if ( m_myBSfile.eof() ) break; 
+       uint32_t word=0;
        m_myBSfile.read ((char*)&word, sizeof(word));
-       if (word==m_checkword) {
-	  nevents+=1;
-       }
+       if ( word == m_checkword )  m_Nevents_BS++;
     }
     m_myBSfile.clear();
     m_myBSfile.seekg(0,std::ios::beg);
-    return nevents;    
-}
-void CompareFTKEvents::PrintFiles()
-{
-    std::cout<<"Print Input files"<<std::endl;
-    std::cout<<m_BSfile<<std::endl;
-    std::cout<<m_NTUP_FTK_file<<std::endl;    
+
+    std::cout<<"Info. Input BS file has "<<m_Nevents_BS<<" events."<<std::endl;
+    return true;    
 }
+
+
+// ________________________________________________________________ //
 CompareFTKEvents::~CompareFTKEvents()
 {
     m_myBSfile.close();
-    if (m_allmatched) std::cout<<"====>Finished successfully: the two files contain the same infos"<<std::endl;
-    else std::cout<<"====>There was something different, check the printouts"<<std::endl;
+    if (m_allmatched) 
+       std::cout<<"====> Finished successfully: the two files contain the same infos."<<std::endl;
+    else 
+       std::cout<<"====> Something went wrong. Please check the printouts."<<std::endl;
     
 }
diff --git a/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKTracks.cxx b/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKTracks.cxx
index ea370c7e72d3..4c97ca3ef071 100644
--- a/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKTracks.cxx
+++ b/Trigger/TrigFTK/FTKStandaloneMonitoring/src/CompareFTKTracks.cxx
@@ -4,12 +4,14 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 #include "FTKStandaloneMonitoring/CompareFTKTracks.h"
 #include <iostream>
 #include <string>
+
 CompareFTKTracks::CompareFTKTracks(std::vector<const FTK_RawTrack *> &ref, std::vector<const FTK_RawTrack *> &test, std::map<std::string , TH1D * > &map_histo, std::map<std::string , TH2D * > &map_histo_2D){
       m_ref=ref;
       m_test=test;
       m_map_histo=map_histo;
       m_map_histo_2D=map_histo_2D;
 }
+
 void CompareFTKTracks::AssociateTracks(){
       m_associator= new FTKTrkAssoc("FTKTrkAssoc", m_dmax);
       m_associator->match( m_ref,m_test);
@@ -31,6 +33,7 @@ void CompareFTKTracks::TestEquivalence(){
       if (m_allmatched) std::cout<<"CompareFTKTracks: All matched tracks had the same phi"<<std::endl;
       else std::cout<<"CompareFTKTracks: Some matched tracks had different phi"<<std::endl;
 }
+
 double CompareFTKTracks::GetValue(std::string & variable, const FTK_RawTrack  *tmptrk){
      double outvar=0.;
      if (variable.find("pt")!=std::string::npos)        {outvar= 1./tmptrk->getInvPt();}
@@ -42,6 +45,7 @@ double CompareFTKTracks::GetValue(std::string & variable, const FTK_RawTrack  *t
      else std::cout<<"variable not found!! "<<variable<<std::endl;
      return outvar;
 }
+
 void CompareFTKTracks::FillHistos(){
       const FTK_RawTrack* match_track = NULL;
       int itrk=0;
@@ -49,6 +53,7 @@ void CompareFTKTracks::FillHistos(){
       int HWSWdifferent=0;
       int HWonly=0;
       int SWonly=0;
+      // filling the SWonly histograms by looping over the test tracks
       for(auto& test_track : m_test){
           match_track = m_associator->revmatched(test_track);
 	  if (!match_track) {
@@ -72,10 +77,12 @@ void CompareFTKTracks::FillHistos(){
 	     SWonly+=1;	      
 	  }    
       }  
+      
+      // loop over the reference tracks
       for(auto& ref_track : m_ref){
          itrk+=1;
          match_track = m_associator->matched(ref_track);
-	 //no SW matched track
+	 //no SW matched track -> HWonly histograms
 	 if (!match_track) {
 	     std::cout<<"the "<<itrk<<"-th HW track has no matched track"<<std::endl; 
              for (auto& imap : m_map_histo){
@@ -96,7 +103,7 @@ void CompareFTKTracks::FillHistos(){
              }
 	     HWonly+=1;
 	 }
-	 //completely matched tracks    
+	 //completely matched tracks : HWSW histograms   
 	 else if (!(
 	      (ref_track->getPhi()!=0&&fabs(match_track->getPhi()/ref_track->getPhi()-1.)>0.001)||
 	      (ref_track->getInvPt()!=0&&fabs(match_track->getInvPt()/ref_track->getInvPt()-1.)>0.001)||
@@ -125,7 +132,7 @@ void CompareFTKTracks::FillHistos(){
              
 	     HWSWmatched+=1;
 	 }
-	 //not matched tracks
+	 //not matched tracks -> HWvsSW histograms
 	 else{
 	     for (auto& imap : m_map_histo){
 	        if (imap.first.find("HWvsSW")==std::string::npos && imap.first.find("res")==std::string::npos) continue;
@@ -158,8 +165,13 @@ void CompareFTKTracks::FillHistos(){
 	     HWSWdifferent+=1;
 	 }   
       }
+      //histogram cointaining the number of SW tracks not matched to any HW track per event
       m_map_histo["nTrk_only_sw"]->Fill(SWonly); 
+      //histogram cointaining the number of HW tracks not matched to any SW track per event
       m_map_histo["nTrk_only_hw"]->Fill(HWonly); 
+      //histogram cointaining the number of HW tracks not completely matched 
+      // to SW tracks per event (some differences in the track paramters)
       m_map_histo["nTrk_different_hw_sw"]->Fill(HWSWdifferent); 
+      //histogram cointaining the number of HW tracks completely matched to SW tracks per event
       m_map_histo["nTrk_same_hw_sw"]->Fill(HWSWmatched); 
 }
diff --git a/Trigger/TrigFTK/FTKStandaloneMonitoring/test/MonitoringComparison.cxx b/Trigger/TrigFTK/FTKStandaloneMonitoring/test/MonitoringComparison.cxx
index 5e4adc323993..6ebcd823f3ef 100644
--- a/Trigger/TrigFTK/FTKStandaloneMonitoring/test/MonitoringComparison.cxx
+++ b/Trigger/TrigFTK/FTKStandaloneMonitoring/test/MonitoringComparison.cxx
@@ -18,6 +18,7 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 #include "TrigFTKSim/FTKTrackStream.h"
 #include "FTKStandaloneMonitoring/FTKTrkAssoc.h"
 #include "FTKStandaloneMonitoring/CompareFTKEvents.h"
+#include <ipc/core.h>
 
 using namespace std;
 
@@ -34,9 +35,7 @@ using namespace std;
 // Globals
 int verbose = FALSE;
 int readfile = FALSE;
-char filename[200] = {0};
-
-
+char filename[1000] = {0};
 
 /**************/
 void usage(void)
@@ -47,6 +46,8 @@ void usage(void)
   std::cout << "-n x: Read NTUP_FTK data from file. The parameter is the path and the name of the file" << std::endl;
   std::cout << "-m x: maximum number of events" << std::endl;
   std::cout << "-v  : Verbose output                               -> Default: FALSE" << std::endl;
+  std::cout << "-p x: partition name" << std::endl;
+  std::cout << "-s  : not to initialize a partition" << std::endl;
   std::cout << std::endl;
 }
 
@@ -57,14 +58,16 @@ int main(int argc, char **argv)
 /*****************************/
 {
 
+  std::string  partition_name="";
   //default files
   std::string inputfilenameBS= "/afs/cern.ch/user/g/giulini/workdir/public/FTKcomparison/compareInputs/OUT.BS_FTK.root";
   std::string inputfilenameNTUPFTK= "/afs/cern.ch/user/g/giulini/workdir/public/FTKcomparison/compareInputs/OUT.NTUP_FTK.root";
   //evtinfo TTree NTUP_FTK
   int c;
   int evtmax=0;
+  bool setup_partition=true;
   static struct option long_options[] = {"DVS", no_argument, NULL, '1'}; 
-  while ((c = getopt_long(argc, argv, "f:n:m:vh", long_options, NULL)) != -1)
+  while ((c = getopt_long(argc, argv, "f:n:m:p:svh", long_options, NULL)) != -1)
     switch (c) 
     {
     case 'h':
@@ -88,12 +91,21 @@ int main(int argc, char **argv)
       inputfilenameNTUPFTK.append(filename);
       std::cout << "read NTUP_FTK data from file: "<< std::endl << inputfilenameNTUPFTK<< std::endl << std::endl;
       break;
-            
+
+    case 'p':   
+      sscanf(optarg,"%s", filename);
+      partition_name.clear();
+      partition_name.append(filename);
+      std::cout << "parition name: " << std::endl<< partition_name<< std::endl << std::endl;
+      break;
+      
     case 'm':   
       sscanf(optarg,"%d", &evtmax);
       std::cout << "maximum number of events: "<< evtmax << std::endl << std::endl;
       break;
       
+    case 's': setup_partition = false;  break;
+
     case 'v': verbose = TRUE;  break;
 
 
@@ -105,11 +117,18 @@ int main(int argc, char **argv)
     }
   ;
 
+  try {
+     IPCCore::init( argc, argv );
+  }
+  catch( daq::ipc::Exception & ex ) {
+      //something went very bad, report and exit
+      std::cout<<"ERROR: IPCCore could not be initialised"<<std::endl;
+      return 1;
+  }
 
   // initialization of the class to compare FTK events of HW (BS_FTK) and SW (NTUP_FTK)
-  CompareFTKEvents *comparison= new CompareFTKEvents(inputfilenameBS,inputfilenameNTUPFTK);
-  if (verbose) comparison->SetVerbose();  
-  if (evtmax!=0)    comparison->SetNEvents(evtmax);
+  CompareFTKEvents comparison(inputfilenameBS,inputfilenameNTUPFTK);
+  if (verbose) comparison.SetVerbose();  
   // create list of histograms to be published on oh
   std::vector<std::string> variable_list={"pt","eta","phi","d0","z0","chi2","ETA_PHI"};//  
   std::vector<std::string> histo_list;
@@ -141,8 +160,10 @@ int main(int argc, char **argv)
   histo_list.push_back("nTrk_only_sw");
   histo_list.push_back("nTrk_HW");
   histo_list.push_back("nTrk_SW");
-  comparison->SetHistos(histo_list);
-  comparison->Execute();      
+  comparison.SetHistos(histo_list);
+  comparison.ExecuteEventLoop(evtmax);
+  if (setup_partition) comparison.PublishHistosToPartition(partition_name);
+  comparison.WriteHistosToFile();
   return 0;
 }
 
diff --git a/Trigger/TrigFTK/FastTrackSimWrap/CMakeLists.txt b/Trigger/TrigFTK/FastTrackSimWrap/CMakeLists.txt
index 2dcf38425f22..77f718a488a6 100644
--- a/Trigger/TrigFTK/FastTrackSimWrap/CMakeLists.txt
+++ b/Trigger/TrigFTK/FastTrackSimWrap/CMakeLists.txt
@@ -17,6 +17,7 @@ atlas_depends_on_subdirs( PUBLIC
                           Tracking/TrkEvent/TrkTrack
                           Tracking/TrkEvent/TrkTruthData
                           Tracking/TrkTools/TrkToolInterfaces
+                          Tracking/TrkFitter/TrkFitterInterfaces
                           Tracking/TrkTools/TrkTrackSummaryTool
                           Trigger/TrigAnalysis/TrigDecisionTool
                           Trigger/TrigEvent/TrigCaloEvent
@@ -37,6 +38,7 @@ atlas_depends_on_subdirs( PUBLIC
                           InnerDetector/InDetDetDescr/SCT_Cabling
                           InnerDetector/InDetRawEvent/InDetRawData
                           InnerDetector/InDetRawEvent/InDetSimData
+                          InnerDetector/InDetRecEvent/InDetRIO_OnTrack
                           TileCalorimeter/TileIdentifier
 			  Tracking/TrkFitter/TrkFitterInterfaces
                           Tracking/TrkEvent/TrkRIO_OnTrack
diff --git a/Trigger/TrigFTK/FastTrackSimWrap/FastTrackSimWrap/FTKRegionalWrapper.h b/Trigger/TrigFTK/FastTrackSimWrap/FastTrackSimWrap/FTKRegionalWrapper.h
index eb779d9ab070..0e14b3e251aa 100644
--- a/Trigger/TrigFTK/FastTrackSimWrap/FastTrackSimWrap/FTKRegionalWrapper.h
+++ b/Trigger/TrigFTK/FastTrackSimWrap/FastTrackSimWrap/FTKRegionalWrapper.h
@@ -16,7 +16,8 @@
 #include "InDetReadoutGeometry/SiDetectorElementCollection.h"
 #include "SCT_Cabling/ISCT_CablingTool.h"
 #include "StoreGate/ReadCondHandleKey.h"
-
+#include "InDetReadoutGeometry/SiDetectorElementCollection.h"
+#include "StoreGate/ReadCondHandleKey.h"
 #include "TrigFTKToolInterfaces/ITrigFTKClusterConverterTool.h"
 #include "TrigFTKTrackConverter/TrigFTKClusterConverterTool.h"
 
@@ -69,20 +70,22 @@ private:
   const PixelID * m_pixelId;
   const SCT_ID * m_sctId;
   const AtlasDetectorID* m_idHelper;
-  const InDetDD::PixelDetectorManager*  m_PIX_mgr;
 
+  const InDetDD::PixelDetectorManager*  m_PIX_mgr;
   SG::ReadCondHandleKey<InDetDD::SiDetectorElementCollection> m_SCTDetEleCollKey{this, "SCTDetEleCollKey", "SCT_DetectorElementCollection", "Key of SiDetectorElementCollection for SCT"};
 
+  std::unique_ptr<FTKClusteringEngine> m_clusteringEngine = nullptr;
+
   // variables to manage the distribution of the hits
   int m_IBLMode; //  global FTK setup variable to handle IBL
   bool m_fixEndcapL0; //fix for endcap L0 in clustering
   bool m_ITkMode; //  global FTK setup variable to toggle ITk geometry
   std::string m_pmap_path; //  path of the PMAP file
-  FTKPlaneMap *m_pmap; //  pointer to the pmap object
+  std::unique_ptr<FTKPlaneMap> m_pmap = nullptr; //  pointer to the pmap object
 
   // variables to manage the region maps
   std::string m_rmap_path; //  path of the region-map file
-  FTKRegionMap *m_rmap; //  pointer to the RMAP object
+  std::unique_ptr<FTKRegionMap> m_rmap = nullptr; //  pointer to the RMAP object
   int m_ntowers;
   int m_nplanes;
  
@@ -147,18 +150,17 @@ private:
   std::vector<std::string> m_spix_rodIdlist;  /** List of RodIDs to be used to emulate DF output*/
   std::vector<std::string> m_ssct_rodIdlist;  /** List of RodIDs to be used to emulate DF output*/
 
-  bool dumpFTKTestVectors(FTKPlaneMap *pmap, FTKRegionMap *rmap);
-
+  bool dumpFTKTestVectors(const FTKPlaneMap *pmap, const FTKRegionMap *rmap);
 
   //Added for cluster conversion
   std::string m_FTKPxlClu_CollName;  /** default name for the FTK pixel ID Cluster container */
-  InDet::PixelClusterContainer *m_FTKPxlCluContainer;   /**  FTK pixel ID Cluster container */
+  std::unique_ptr<InDet::PixelClusterContainer> m_FTKPxlCluContainer;   /**  FTK pixel ID Cluster container */
   std::string m_FTKSCTClu_CollName;  /** default name for the FTK sct ID Cluster container */
-  InDet::SCT_ClusterContainer *m_FTKSCTCluContainer;   /**  FTK pixel ID Cluster container */
+  std::unique_ptr<InDet::SCT_ClusterContainer> m_FTKSCTCluContainer;   /**  FTK pixel ID Cluster container */
 
 
-  PRD_MultiTruthCollection* m_ftkPixelTruth; /** FTK Pixel ID Truth collection */
-  PRD_MultiTruthCollection* m_ftkSctTruth; /** FTK SCT ID Truth collection */
+  std::unique_ptr<PRD_MultiTruthCollection> m_ftkPixelTruth; /** FTK Pixel ID Truth collection */
+  std::unique_ptr<PRD_MultiTruthCollection> m_ftkSctTruth; /** FTK SCT ID Truth collection */
   const McEventCollection*  m_mcEventCollection; /** Truth collection */
 
   std::string m_ftkPixelTruthName;  /** name of FTK Pixel ID Truth collection */
@@ -170,8 +172,8 @@ private:
   //offline clusters
   std::vector<float>   *m_offline_locX;
   std::vector<float>   *m_offline_locY;
-  std::vector<int>     *m_offline_isPixel;
-  std::vector<int>     *m_offline_isBarrel;
+  std::vector<bool>    *m_offline_isPixel;
+  std::vector<bool>    *m_offline_isBarrel;
   std::vector<int>     *m_offline_layer;
   std::vector<int>     *m_offline_resAssociatedTrack;
   std::vector<int>     *m_offline_clustID;
@@ -182,7 +184,6 @@ private:
   std::vector<float>   *m_offline_eta;
   std::vector<float>   *m_offline_phi;
 
-
   TTree *m_offline_cluster_tree;
 
 };
diff --git a/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_32TowersIBL3DTest_DFTestVectors_jobOptions.py b/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_32TowersIBL3DTest_DFTestVectors_jobOptions.py
index 7cf4af52e4c3..e9ba31b5690f 100755
--- a/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_32TowersIBL3DTest_DFTestVectors_jobOptions.py
+++ b/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_32TowersIBL3DTest_DFTestVectors_jobOptions.py
@@ -49,6 +49,8 @@ wrapper.EmulateDF = True
 wrapper.SaveRawHits = True
 wrapper.SaveHits = True
 wrapper.DuplicateGanged = False
+wrapper.SctClustering=True
+
 print "FTKRegionalWrapper setting ROBS"
 wrapper.pixRodIds = ["0x112414", "0x140170", "0x111816", "0x112411", "0x112416", "0x140140", "0x140180", "0x130011"]
 wrapper.sctRodIds = ["0x210000", "0x210109", "0x210108", "0x230100", "0x220000", "0x220109", "0x22010a", "0x21010a"]
diff --git a/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_64TowersIBL3D_HWModeID2_jobOptions.py b/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_64TowersIBL3D_HWModeID2_jobOptions.py
index bf03f291b01c..86e6a490f985 100644
--- a/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_64TowersIBL3D_HWModeID2_jobOptions.py
+++ b/Trigger/TrigFTK/FastTrackSimWrap/share/FastTrackSimRegionalWrap_64TowersIBL3D_HWModeID2_jobOptions.py
@@ -37,13 +37,15 @@ wrapper = FTKRegionalWrapper(OutputLevel = DEBUG,
                              RMapPath = rmap_path,
                              OutFileName = OutputNTUP_FTKIPFile)
 wrapper.IBLMode = 2
-wrapper.FixEndcapL0 = False
+wrapper.FixEndcapL0 = True
 wrapper.HitInputTool = FTKSGInput
 wrapper.PixelClusteringMode = 101
 wrapper.Ibl3DRealistic = False
 wrapper.SctClustering = True
 wrapper.Clustering = True
 
+wrapper.GetOffline = False
+
 theJob += wrapper
 
 print theJob
diff --git a/Trigger/TrigFTK/FastTrackSimWrap/src/FTKRegionalWrapper.cxx b/Trigger/TrigFTK/FastTrackSimWrap/src/FTKRegionalWrapper.cxx
index 827ef98bec19..9a978a8bf87f 100644
--- a/Trigger/TrigFTK/FastTrackSimWrap/src/FTKRegionalWrapper.cxx
+++ b/Trigger/TrigFTK/FastTrackSimWrap/src/FTKRegionalWrapper.cxx
@@ -4,7 +4,7 @@
 #include "xAODTracking/TrackParticleContainer.h"
 #include "FastTrackSimWrap/FTKRegionalWrapper.h"
 #include "TrigFTKSim/FTKDataInput.h"
-#include "TrigFTKSim/atlClustering.h"
+#include "TrigFTKSim/FTKClusteringEngine.h"
 
 #include "TrkTruthData/PRD_MultiTruthCollection.h"
 
@@ -14,9 +14,7 @@
 #include "PixelCabling/IPixelCablingSvc.h"
 #include "SCT_Cabling/SCT_OnlineId.h"
 #include "InDetRIO_OnTrack/SiClusterOnTrack.h"
-
 #include "InDetReadoutGeometry/PixelDetectorManager.h"
-
 #include "InDetIdentifier/PixelID.h"
 #include "InDetIdentifier/SCT_ID.h"
 #include "Identifier/Identifier.h"
@@ -40,199 +38,197 @@ using std::dec;
 using std::setprecision;
 using std::setw;
 
-
 FTKRegionalWrapper::FTKRegionalWrapper (const std::string& name, ISvcLocator* pSvcLocator) :
-  AthAlgorithm(name, pSvcLocator), 
-  m_hitInputTool("FTK_SGHitInput/FTK_SGHitInput"),
-  m_clusterConverterTool("TrigFTKClusterConverterTool"),
-  m_pix_cabling_svc("PixelCablingSvc", name),
-  m_sct_cablingToolInc("SCT_CablingToolInc"),
-  m_storeGate(0),
-  m_detStore( 0 ),
-  m_evtStore(0 ),
-  m_pixelId(0),
-  m_sctId(0),
-  m_idHelper(0),
-  m_PIX_mgr(0),
-  m_IBLMode(0),
-  m_fixEndcapL0(false),
-  m_ITkMode(false),
-  m_pmap_path(""),
-  m_pmap(0x0),
-  m_rmap_path(""),
-  m_rmap(0x0),
-  m_ntowers(0),
-  m_nplanes(12),
-  m_SaveRawHits(true),
-  m_SaveHits(false),
-  m_SavePerPlane(false),
-  m_DumpTestVectors(false),
-  m_EmulateDF(false),
-  m_Clustering(false),
-  m_SaveClusterContent(false),
-  m_DiagClustering(true),
-  m_SctClustering(false),
-  m_PixelClusteringMode(1),
-  m_Ibl3DRealistic(false),
-  m_DuplicateGanged(true),
-  m_GangedPatternRecognition(false),
-  m_WriteClustersToESD(false),
-  m_getOffline(false),
-  m_offlineName("InDetTrackParticles"),
-  m_outpath("ftksim_smartwrapper.root"),
-  m_outfile(0x0),
-  m_hittree(0x0),
-  m_hittree_perplane(0),
-  m_original_hits(0),
-  m_logical_hits(0),
-  m_original_hits_per_plane(0),
-  m_logical_hits_per_plane(0),
-  m_evtinfo(0),
-  m_run_number(0),
-  m_event_number(0),
-  m_trackstree(0),
-  m_identifierHashList(0x0),
+    AthAlgorithm(name, pSvcLocator),
+    m_hitInputTool("FTK_SGHitInput/FTK_SGHitInput"),
+    m_clusterConverterTool("TrigFTKClusterConverterTool"),
+    m_pix_cabling_svc("PixelCablingSvc", name),
+    m_sct_cablingToolInc("SCT_CablingToolInc"),
+    m_storeGate(0),
+    m_detStore( 0 ),
+    m_evtStore(0 ),
+    m_pixelId(0),
+    m_sctId(0),
+    m_idHelper(0),
+    m_PIX_mgr(0),
+    m_IBLMode(0),
+    m_fixEndcapL0(false),
+    m_ITkMode(false),
+    m_pmap_path(""),
+    m_pmap(nullptr),
+    m_rmap_path(""),
+    m_rmap(nullptr),
+    m_ntowers(0),
+    m_nplanes(12),
+    m_SaveRawHits(true),
+    m_SaveHits(false),
+    m_SavePerPlane(false),
+    m_DumpTestVectors(false),
+    m_EmulateDF(false),
+    m_Clustering(false),
+    m_SaveClusterContent(false),
+    m_DiagClustering(true),
+    m_SctClustering(false),
+    m_PixelClusteringMode(1),
+    m_Ibl3DRealistic(false),
+    m_DuplicateGanged(true),
+    m_GangedPatternRecognition(false),
+    m_WriteClustersToESD(false),
+    m_getOffline(false),
+    m_offlineName("InDetTrackParticles"),
+    m_outpath("ftksim_smartwrapper.root"),
+    m_outfile(0x0),
+    m_hittree(0x0),
+    m_hittree_perplane(0),
+    m_original_hits(0),
+    m_logical_hits(0),
+    m_original_hits_per_plane(0),
+    m_logical_hits_per_plane(0),
+    m_evtinfo(0),
+    m_run_number(0),
+    m_event_number(0),
+    m_trackstree(0),
+    m_identifierHashList(0x0),
 //  m_pix_rodIdlist({0x130011, 0x111510, 0x111508, 0x112414, 0x130015, 0x111716, 0x112416}),  //old ROD list for consistency.  to be removed soon.
 //  m_sct_rodIdlist({0x220005, 0x210005, 0x220007}),
 
-  //run II configuration for towers 44 & 45 (DF Crate 3 slot 9)
-  //m_pix_rodIdlist({0x140160, 0x130007, 0x112508, 0x111816, 0x140170, 0x130015,0x112414}),
-  //m_sct_rodIdlist({0x21010d, 0x21010c, 0x21010e,0x21010f}),
-
-  //run 1 configuration for towers 44 & 45 (DF Crate 3 slot 9)
-  //m_pix_rodIdlist({0x130007, 0x111510, 0x111816, 0x111508,0x112414}),
-  //m_sct_rodIdlist({0x21010a, 0x210000}),
-
-  //AUX test vector configuration for tower 44 & 45 (DF Crate 3 slot 9)
-  //m_pix_rodIdlist({0x130007, 0x112510, 0x111816, 0x112508,0x112414}),
-  //m_sct_rodIdlist({0x21010a, 0x210000}),
-
-  //  m_pix_rodIdlist({0x130007, 0x111510, 0x111816, 0x111508,0x112414,0x1400a3,0x130010,0x130011,0x112508,0x112510}),
-  // m_sct_rodIdlist({0x21010a, 0x210000, 0x210109}),
-
-  m_pix_rodIdlist({0x112414, 0x140170, 0x111816, 0x112411, 0x112416, 0x140140, 0x140180, 0x130011}),
-  m_sct_rodIdlist({0x210000, 0x210109, 0x210108, 0x230100, 0x220000, 0x220109, 0x22010a, 0x21010a}),
-
-  m_spix_rodIdlist({"0x112414", "0x140170", "0x111816", "0x112411", "0x112416", "0x140140", "0x140180", "0x130011"}),
-  m_ssct_rodIdlist({"0x210000", "0x210109", "0x210108", "0x230100", "0x220000", "0x220109", "0x22010a", "0x21010a"}),
-
-  m_FTKPxlClu_CollName("FTK_Pixel_Clusters"), 
-  m_FTKPxlCluContainer(0x0),
-  m_FTKSCTClu_CollName("FTK_SCT_Cluster"),
-  m_FTKSCTCluContainer(0x0),
-  m_ftkPixelTruthName("PRD_MultiTruthPixel_FTK"),
-  m_ftkSctTruthName("PRD_MultiTruthSCT_FTK"),
-  m_mcTruthName("TruthEvent"),
-  m_L1ID_to_save(std::vector<int>()),
-  m_offline_locX(nullptr),
-  m_offline_locY(nullptr),
-  m_offline_isPixel(nullptr),
-  m_offline_isBarrel(nullptr),
-  m_offline_layer(nullptr),
-  m_offline_clustID(nullptr),
-  m_offline_trackNumber(nullptr),
-  m_offline_pt(nullptr),
-  m_offline_eta(nullptr),
-  m_offline_phi(nullptr),
-  m_offline_cluster_tree(nullptr)
+    //run II configuration for towers 44 & 45 (DF Crate 3 slot 9)
+    //m_pix_rodIdlist({0x140160, 0x130007, 0x112508, 0x111816, 0x140170, 0x130015,0x112414}),
+    //m_sct_rodIdlist({0x21010d, 0x21010c, 0x21010e,0x21010f}),
+
+    //run 1 configuration for towers 44 & 45 (DF Crate 3 slot 9)
+    //m_pix_rodIdlist({0x130007, 0x111510, 0x111816, 0x111508,0x112414}),
+    //m_sct_rodIdlist({0x21010a, 0x210000}),
+
+    //AUX test vector configuration for tower 44 & 45 (DF Crate 3 slot 9)
+    //m_pix_rodIdlist({0x130007, 0x112510, 0x111816, 0x112508,0x112414}),
+    //m_sct_rodIdlist({0x21010a, 0x210000}),
+
+    //  m_pix_rodIdlist({0x130007, 0x111510, 0x111816, 0x111508,0x112414,0x1400a3,0x130010,0x130011,0x112508,0x112510}),
+    // m_sct_rodIdlist({0x21010a, 0x210000, 0x210109}),
+
+    m_pix_rodIdlist({0x112414, 0x140170, 0x111816, 0x112411, 0x112416, 0x140140, 0x140180, 0x130011}),
+    m_sct_rodIdlist({0x210000, 0x210109, 0x210108, 0x230100, 0x220000, 0x220109, 0x22010a, 0x21010a}),
+
+    m_spix_rodIdlist({"0x112414", "0x140170", "0x111816", "0x112411", "0x112416", "0x140140", "0x140180", "0x130011"}),
+    m_ssct_rodIdlist({"0x210000", "0x210109", "0x210108", "0x230100", "0x220000", "0x220109", "0x22010a", "0x21010a"}),
+
+    m_FTKPxlClu_CollName("FTK_Pixel_Clusters"),
+    m_FTKPxlCluContainer(nullptr),
+    m_FTKSCTClu_CollName("FTK_SCT_Cluster"),
+    m_FTKSCTCluContainer(nullptr),
+    m_ftkPixelTruthName("PRD_MultiTruthPixel_FTK"),
+    m_ftkSctTruthName("PRD_MultiTruthSCT_FTK"),
+    m_mcTruthName("TruthEvent"),
+    m_L1ID_to_save(std::vector<int>()),
+    m_offline_locX(nullptr),
+    m_offline_locY(nullptr),
+    m_offline_isPixel(nullptr),
+    m_offline_isBarrel(nullptr),
+    m_offline_layer(nullptr),
+    m_offline_clustID(nullptr),
+    m_offline_trackNumber(nullptr),
+    m_offline_pt(nullptr),
+    m_offline_eta(nullptr),
+    m_offline_phi(nullptr),
+    m_offline_cluster_tree(nullptr)
 {
-  
-  declareProperty("TrigFTKClusterConverterTool", m_clusterConverterTool);
-  declareProperty("RMapPath",m_rmap_path);
-  declareProperty("PMapPath",m_pmap_path);
-  declareProperty("OutFileName",m_outpath);
-  declareProperty("HitInputTool",m_hitInputTool);
-  declareProperty("IBLMode",m_IBLMode);
-  declareProperty("FixEndcapL0", m_fixEndcapL0);
-  declareProperty("ITkMode",m_ITkMode);
-  declareProperty("PixelCablingSvc", m_pix_cabling_svc);
-  declareProperty("SCT_CablingTool",m_sct_cablingToolInc);
-
-  // hit type options
-  declareProperty("SaveRawHits",m_SaveRawHits);
-  declareProperty("SaveHits",m_SaveHits);
-
-  // special options for test vector production
-  declareProperty("SavePerPlane",m_SavePerPlane);
-  declareProperty("DumpTestVectors",m_DumpTestVectors);
-  
-  declareProperty("GetOffline",m_getOffline);
-  declareProperty("OfflineName",m_offlineName);
-
-  // clustering options
-  declareProperty("Clustering",m_Clustering);
-  declareProperty("SaveClusterContent",m_SaveClusterContent);
-  declareProperty("DiagClustering",m_DiagClustering);
-  declareProperty("SctClustering",m_SctClustering);
-  declareProperty("PixelClusteringMode",m_PixelClusteringMode);
-  declareProperty("Ibl3DRealistic",m_Ibl3DRealistic);
-  declareProperty("DuplicateGanged",m_DuplicateGanged);
-  declareProperty("GangedPatternRecognition",m_GangedPatternRecognition);
-
-
-  //output for PseduoTracking
-  declareProperty("WriteClustersToESD",m_WriteClustersToESD);
-  declareProperty("FTKPixelClustersCollName",m_FTKPxlClu_CollName,"FTK pixel clusters collection");
-  declareProperty("FTKSCTClusterCollName",m_FTKSCTClu_CollName,"FTK SCT clusters collection");
-
-  //for DF board emulation 
-  declareProperty("EmulateDF",m_EmulateDF);
-  declareProperty("pixRodIds", m_spix_rodIdlist);
-  declareProperty("sctRodIds", m_ssct_rodIdlist);
-  declareProperty("L1IDToSave", m_L1ID_to_save);
+
+    declareProperty("TrigFTKClusterConverterTool", m_clusterConverterTool);
+    declareProperty("RMapPath",m_rmap_path);
+    declareProperty("PMapPath",m_pmap_path);
+    declareProperty("OutFileName",m_outpath);
+    declareProperty("HitInputTool",m_hitInputTool);
+    declareProperty("IBLMode",m_IBLMode);
+    declareProperty("FixEndcapL0", m_fixEndcapL0);
+    declareProperty("ITkMode",m_ITkMode);
+    declareProperty("PixelCablingSvc", m_pix_cabling_svc);
+    declareProperty("SCT_CablingTool",m_sct_cablingToolInc);
+
+    // hit type options
+    declareProperty("SaveRawHits",m_SaveRawHits);
+    declareProperty("SaveHits",m_SaveHits);
+
+    // special options for test vector production
+    declareProperty("SavePerPlane",m_SavePerPlane);
+    declareProperty("DumpTestVectors",m_DumpTestVectors);
+
+    declareProperty("GetOffline",m_getOffline);
+    declareProperty("OfflineName",m_offlineName);
+
+    // clustering options
+    declareProperty("Clustering",m_Clustering);
+    declareProperty("SaveClusterContent",m_SaveClusterContent);
+    declareProperty("DiagClustering",m_DiagClustering);
+    declareProperty("SctClustering",m_SctClustering);
+    declareProperty("PixelClusteringMode",m_PixelClusteringMode);
+    declareProperty("Ibl3DRealistic",m_Ibl3DRealistic);
+    declareProperty("DuplicateGanged",m_DuplicateGanged);
+    declareProperty("GangedPatternRecognition",m_GangedPatternRecognition);
+
+
+    //output for PseduoTracking
+    declareProperty("WriteClustersToESD",m_WriteClustersToESD);
+    declareProperty("FTKPixelClustersCollName",m_FTKPxlClu_CollName,"FTK pixel clusters collection");
+    declareProperty("FTKSCTClusterCollName",m_FTKSCTClu_CollName,"FTK SCT clusters collection");
+
+    //for DF board emulation
+    declareProperty("EmulateDF",m_EmulateDF);
+    declareProperty("pixRodIds", m_spix_rodIdlist);
+    declareProperty("sctRodIds", m_ssct_rodIdlist);
+    declareProperty("L1IDToSave", m_L1ID_to_save);
 }
 
 FTKRegionalWrapper::~FTKRegionalWrapper ()
 {
-  if (m_rmap) delete m_rmap;
+
 }
 
 StatusCode FTKRegionalWrapper::initialize()
 {
-  MsgStream log(msgSvc(), name());
-  log << MSG::INFO << "FTKRegionalWrapper::initialize()" << endmsg;
+  ATH_MSG_VERBOSE("FTKRegionalWrapper::initialize()");
 
   // FTK library global setup variables
   FTKSetup::getFTKSetup().setIBLMode(m_IBLMode);
   FTKSetup::getFTKSetup().setfixEndcapL0(m_fixEndcapL0);
   FTKSetup::getFTKSetup().setITkMode(m_ITkMode);
 
-  log << MSG::INFO << "Read the logical layer definitions" << endmsg;
+  ATH_MSG_VERBOSE("Read the logical layer definitions");
   // Look for the main plane-map
   if (m_pmap_path.empty()) {
-    log << MSG::FATAL << "Main plane map definition missing" << endmsg;
+    ATH_MSG_FATAL("Main plane map definition missing");
     return StatusCode::FAILURE;
   }
   else {
-    m_pmap = new FTKPlaneMap(m_pmap_path.c_str());
-    if (!(*m_pmap)) {
-      log << MSG::FATAL << "Error using plane map: " << m_pmap_path << endmsg;
+      m_pmap = std::make_unique<FTKPlaneMap>(m_pmap_path.c_str());
+    if (m_pmap == nullptr) {
+      ATH_MSG_FATAL("Error using plane map: " << m_pmap_path);
       return StatusCode::FAILURE;
     }
   }
 
   // initialize the tower/region map
-  log << MSG::INFO << "Creating region map" << endmsg;
-  m_rmap = new FTKRegionMap(m_pmap, m_rmap_path.c_str());
-  if (!(*m_rmap)) {
-    log << MSG::FATAL << "Error creating region map from: " << m_rmap_path.c_str() << endmsg;
+  ATH_MSG_VERBOSE("Creating region map");
+  m_rmap = std::make_unique<FTKRegionMap>(m_pmap.get(), m_rmap_path.c_str());
+  if (m_rmap == nullptr) {
+    ATH_MSG_FATAL("Error creating region map from: " << m_rmap_path.c_str());
     return StatusCode::FAILURE;
   }
 
   StatusCode schit = m_hitInputTool.retrieve();
   if (schit.isFailure()) {
-    log << MSG::FATAL << "Could not retrieve FTK_SGHitInput tool" << endmsg;
+    ATH_MSG_FATAL("Could not retrieve FTK_SGHitInput tool");
     return StatusCode::FAILURE;
   }
   else {
-    log << MSG::INFO << "Setting FTK_SGHitInput tool" << endmsg;
+    ATH_MSG_VERBOSE("Setting FTK_SGHitInput tool");
     // set the pmap address to FTKDataInput to use in processEvent
-    m_hitInputTool->reference()->setPlaneMaps(m_pmap,0x0);
+    m_hitInputTool->reference()->setPlaneMaps(m_pmap.get(),0x0);
   }
 
   // Get the cluster converter tool
   if (m_clusterConverterTool.retrieve().isFailure() ) {
-    log << MSG::ERROR << "Failed to retrieve tool " << m_clusterConverterTool << endmsg;
+    ATH_MSG_ERROR("Failed to retrieve tool " << m_clusterConverterTool);
     return StatusCode::FAILURE;
   }
 
@@ -240,64 +236,63 @@ StatusCode FTKRegionalWrapper::initialize()
   if( m_ITkMode ) {
     // Pixel Cabling database not ready
     // Ignore this error but make sure everything that uses the cabling database is off
-    log << MSG::WARNING << "ITkMode is set to True --> not loading Pixel Cabling Svc" << endmsg;
+    ATH_MSG_WARNING("ITkMode is set to True --> not loading Pixel Cabling Svc");
     if( m_DumpTestVectors || m_EmulateDF ) {
-      log << MSG::FATAL << "PixelCabling not initialized so m_DumpTestVectors and m_EmulateDF must both be set to false!" << endmsg;
+      ATH_MSG_FATAL("PixelCabling not initialized so m_DumpTestVectors and m_EmulateDF must both be set to false!");
       return StatusCode::FAILURE;
     }
   } else if (m_pix_cabling_svc.retrieve().isFailure()) {
-    log << MSG::FATAL << "Failed to retrieve tool " << m_pix_cabling_svc << endmsg;
+    ATH_MSG_FATAL("Failed to retrieve tool " << m_pix_cabling_svc);
     return StatusCode::FAILURE;
   } else {
-    log << MSG::INFO << "Retrieved tool " << m_pix_cabling_svc << endmsg;
+    ATH_MSG_VERBOSE("Retrieved tool " << m_pix_cabling_svc);
   }
-  
+
   // Retrieve sct cabling service
   if( m_ITkMode ) {
     // SCT Cabling database not ready
     // Ignore this error but make sure everything that uses the cabling database is off
-    log << MSG::WARNING << "ITkMode is set to True --> not loading SCT Cabling Svc" << endmsg;
+    ATH_MSG_WARNING("ITkMode is set to True --> not loading SCT Cabling Svc");
     if( m_DumpTestVectors || m_EmulateDF ) {
-      log << MSG::FATAL << "SCT_Cabling not initialized so m_DumpTestVectors and m_EmulateDF must both be set to false!" << endmsg;
+      ATH_MSG_FATAL("SCT_Cabling not initialized so m_DumpTestVectors and m_EmulateDF must both be set to false!");
       return StatusCode::FAILURE;
     }
   } else if (m_sct_cablingToolInc.retrieve().isFailure()) {
-    log << MSG::FATAL << "Failed to retrieve tool " << m_sct_cablingToolInc << endmsg;
+    ATH_MSG_FATAL("Failed to retrieve tool " << m_sct_cablingToolInc);
     return StatusCode::FAILURE;
   } else {
-    log << MSG::INFO << "Retrieved tool " << m_sct_cablingToolInc << endmsg;
+    ATH_MSG_VERBOSE("Retrieved tool " << m_sct_cablingToolInc);
   }
 
   if (!m_SaveRawHits && !m_SaveHits) {
-      log << MSG::FATAL << "At least one hit format has to be saved: FTKRawHit or FTKHit" << endl;
-      return StatusCode::FAILURE;
+    ATH_MSG_FATAL("At least one hit format has to be saved: FTKRawHit or FTKHit");
+    return StatusCode::FAILURE;
   }
 
   // This part retrieves the neccessary pixel/SCT Id helpers. They are intialized by the StoreGateSvc
   if( service("StoreGateSvc", m_storeGate).isFailure() ) {
-     log << MSG::FATAL << "StoreGate service not found" << endmsg;
-     return StatusCode::FAILURE;
-   }
+    ATH_MSG_FATAL("StoreGate service not found");
+    return StatusCode::FAILURE;
+  }
   if( service("DetectorStore",m_detStore).isFailure() ) {
-     log << MSG::FATAL <<"DetectorStore service not found" << endmsg;
-     return StatusCode::FAILURE;
-   }
+    ATH_MSG_FATAL("DetectorStore service not found");
+    return StatusCode::FAILURE;
+  }
   if( m_detStore->retrieve(m_pixelId, "PixelID").isFailure() ) {
-    log << MSG::ERROR << "Unable to retrieve Pixel helper from DetectorStore" << endmsg;
+    ATH_MSG_ERROR("Unable to retrieve Pixel helper from DetectorStore" );
     return StatusCode::FAILURE;
   }
   if( m_detStore->retrieve(m_sctId, "SCT_ID").isFailure() ) {
-    log << MSG::ERROR << "Unable to retrieve Pixel helper from DetectorStore" << endmsg;
+    ATH_MSG_ERROR("Unable to retrieve Pixel helper from DetectorStore" );
     return StatusCode::FAILURE;
   }
-
   if( m_detStore->retrieve(m_idHelper, "AtlasID").isFailure() ) {
-    log << MSG::ERROR << "Unable to retrieve AtlasDetector helper from DetectorStore" << endmsg;
+    ATH_MSG_ERROR("Unable to retrieve AtlasDetector helper from DetectorStore" );
     return StatusCode::FAILURE;
   }
-  
+
   if( m_detStore->retrieve(m_PIX_mgr, "Pixel").isFailure() ) {
-    log << MSG::ERROR << "Unable to retrieve Pixel manager from DetectorStore" << endmsg;
+    ATH_MSG_ERROR("Unable to retrieve Pixel manager from DetectorStore" );
     return StatusCode::FAILURE;
   }
 
@@ -306,80 +301,81 @@ StatusCode FTKRegionalWrapper::initialize()
     ATH_CHECK(m_SCTDetEleCollKey.initialize());
   }
 
+
   // Write clusters in InDetCluster format to ESD for use in Pseudotracking
   if (m_WriteClustersToESD){
     StatusCode sc = service("StoreGateSvc", m_storeGate);
     // Creating collection for pixel clusters
-    m_FTKPxlCluContainer = new InDet::PixelClusterContainer(m_pixelId->wafer_hash_max());
+    m_FTKPxlCluContainer = std::make_unique<InDet::PixelClusterContainer>(m_pixelId->wafer_hash_max());
     m_FTKPxlCluContainer->addRef();
-    sc = m_storeGate->record(m_FTKPxlCluContainer,m_FTKPxlClu_CollName);
+    sc = m_storeGate->record(m_FTKPxlCluContainer.get(), m_FTKPxlClu_CollName);
     if (sc.isFailure()) {
-      log << MSG::FATAL << "Error registering the FTK pixel container in the SG" << endmsg;
+      ATH_MSG_FATAL("Error registering the FTK pixel container in the SG" );
       return StatusCode::FAILURE;
     }
-    
+
     // Generic format link for the pixel clusters
     const InDet::SiClusterContainer *symSiContainerPxl(0x0);
-    sc = m_storeGate->symLink(m_FTKPxlCluContainer,symSiContainerPxl);
+    sc = m_storeGate->symLink(m_FTKPxlCluContainer.get(), symSiContainerPxl);
     if (sc.isFailure()) {
-      log << MSG::FATAL << "Error creating the sym-link to the Pixel clusters" << endmsg;
+      ATH_MSG_FATAL("Error creating the sym-link to the Pixel clusters" );
       return StatusCode::FAILURE;
     }
-    
+
     // Creating collection for the SCT clusters
-    m_FTKSCTCluContainer = new InDet::SCT_ClusterContainer(m_sctId->wafer_hash_max());
+    m_FTKSCTCluContainer = std::make_unique<InDet::SCT_ClusterContainer>(m_sctId->wafer_hash_max());
     m_FTKSCTCluContainer->addRef();
-    sc = m_storeGate->record(m_FTKSCTCluContainer,m_FTKSCTClu_CollName);
+    sc = m_storeGate->record(m_FTKSCTCluContainer.get(), m_FTKSCTClu_CollName);
     if (sc.isFailure()) {
-      log << MSG::FATAL << "Error registering the FTK SCT container in the SG" << endmsg;
+      ATH_MSG_FATAL("Error registering the FTK SCT container in the SG" );
       return StatusCode::FAILURE;
     }
     // Generic format link for the pixel clusters
     const InDet::SiClusterContainer *symSiContainerSCT(0x0);
-    sc = m_storeGate->symLink(m_FTKSCTCluContainer,symSiContainerSCT);
+    sc = m_storeGate->symLink(m_FTKSCTCluContainer.get(), symSiContainerSCT);
     if (sc.isFailure()) {
-      log << MSG::FATAL << "Error creating the sym-link to the SCT clusters" << endmsg;
+      ATH_MSG_FATAL("Error creating the sym-link to the SCT clusters" );
       return StatusCode::FAILURE;
     }
-    
+
     // getting sct truth
-    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkSctTruthName)) { 
-      m_ftkSctTruth = new PRD_MultiTruthCollection;
-      StatusCode sc=m_storeGate->record(m_ftkSctTruth,m_ftkSctTruthName); 
-      if(sc.isFailure()) { 
-	ATH_MSG_WARNING("SCT FTK Truth Container " << m_ftkSctTruthName  
-			<<" cannot be recorded in StoreGate !"); 
-      } 
-      else { 
-	ATH_MSG_DEBUG("SCT FTK Truth Container " << m_ftkSctTruthName   
-		      << " is recorded in StoreGate"); 
-      } 
-    } 
-    //getting pixel truth 
-    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkPixelTruthName)) { 
-      m_ftkPixelTruth = new PRD_MultiTruthCollection;
-      StatusCode sc=m_storeGate->record(m_ftkPixelTruth,m_ftkPixelTruthName); 
-      if(sc.isFailure()) { 
-	ATH_MSG_WARNING("Pixel FTK Truth Container " << m_ftkPixelTruthName  
-			<<" cannot be recorded in StoreGate !"); 
-      } 
-      else { 
-	ATH_MSG_DEBUG("Pixel FTK Truth Container " << m_ftkPixelTruthName   
-		      << " is recorded in StoreGate"); 
-      } 
-    }  
+    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkSctTruthName)) {
+	m_ftkSctTruth = std::make_unique<PRD_MultiTruthCollection>();
+	StatusCode sc=m_storeGate->record(m_ftkSctTruth.get(),m_ftkSctTruthName);
+      if(sc.isFailure()) {
+	ATH_MSG_WARNING("SCT FTK Truth Container " << m_ftkSctTruthName
+			<<" cannot be recorded in StoreGate !");
+      }
+      else {
+	ATH_MSG_DEBUG("SCT FTK Truth Container " << m_ftkSctTruthName
+		      << " is recorded in StoreGate");
+      }
+    }
+    //getting pixel truth
+    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkPixelTruthName)) {
+	m_ftkPixelTruth = std::make_unique<PRD_MultiTruthCollection>();
+	StatusCode sc=m_storeGate->record(m_ftkPixelTruth.get(),m_ftkPixelTruthName);
+      if(sc.isFailure()) {
+	ATH_MSG_WARNING("Pixel FTK Truth Container " << m_ftkPixelTruthName
+			<<" cannot be recorded in StoreGate !");
+      }
+      else {
+	ATH_MSG_DEBUG("Pixel FTK Truth Container " << m_ftkPixelTruthName
+		      << " is recorded in StoreGate");
+      }
+    }
   }
 
 
-  /* initialize the clustering global variables, decalred in TrigFTKSim/atlClusteringLNF.h */
-  SAVE_CLUSTER_CONTENT = m_SaveClusterContent;
-  DIAG_CLUSTERING = m_DiagClustering;
-  SCT_CLUSTERING = m_SctClustering;
-  PIXEL_CLUSTERING_MODE = m_PixelClusteringMode;
-  IBL3D_REALISTIC = m_Ibl3DRealistic;
-  DUPLICATE_GANGED = m_DuplicateGanged;
-  GANGED_PATTERN_RECOGNITION = m_GangedPatternRecognition;
-
+  //Initialize the clustering engine
+  m_clusteringEngine  = std::make_unique<FTKClusteringEngine>(m_SaveClusterContent,
+							    m_DiagClustering,
+							    m_SctClustering,
+							    m_Ibl3DRealistic,
+							    m_DuplicateGanged,
+							    m_GangedPatternRecognition,
+							    false, //splitBlayerModule
+							    m_PixelClusteringMode);
 
   //Dump to the log output the RODs used in the emulation
   if(m_EmulateDF){
@@ -392,6 +388,7 @@ StatusCode FTKRegionalWrapper::initialize()
     }
     ATH_MSG_DEBUG("Printing full SCT map  via m_sct_cablingToolInc->getAllRods()");
     std::vector<uint32_t>  sctVector;
+
     m_sct_cablingToolInc->getAllRods(sctVector);
     ATH_MSG_DEBUG("Printing full SCT map  via m_sct_cablingToolInc->getAllRods() "<<sctVector.size()<<" rods ");
     
@@ -402,7 +399,7 @@ StatusCode FTKRegionalWrapper::initialize()
 
 	for (auto mhit = m_identifierHashList.begin(); mhit != m_identifierHashList.end(); mhit++)
 	  ATH_MSG_DEBUG("SCT  offline map hashID to RobId "<<MSG::dec<<*mhit<<" "<<MSG::hex<<(*mit)<<MSG::dec);
-      }
+    }
 
     m_pix_rodIdlist.clear();
 
@@ -411,27 +408,27 @@ StatusCode FTKRegionalWrapper::initialize()
       str<<(*it);
       int val;
       str>>std::hex>>val;
-      
+
       m_pix_rodIdlist.push_back(val);
 
       ATH_MSG_DEBUG("Going to test against the following Pix RODIDs "<< MSG::hex
 		    << val <<MSG::dec);
-    
-	std::vector<IdentifierHash> offlineIdHashList;
-	m_pix_cabling_svc->getOfflineList(offlineIdHashList, m_pix_cabling_svc->getRobId(val));
-	ATH_MSG_DEBUG("Trying m_pix_cabling_svc->getOfflineList(offlineIdHashList, m_pix_cabling_svc->getRobId("<<MSG::hex<<val<<MSG::dec<<"));");
-	for (auto oit = offlineIdHashList.begin(); oit != offlineIdHashList.end(); oit++){
-
-	    Identifier id = m_pixelId->wafer_id( *oit );
-	    int barrel_ec      = m_pixelId->barrel_ec(id);
-	    int layer_disk     = m_pixelId->layer_disk(id);
-	    int phi_module     = m_pixelId->phi_module(id);
-	    int eta_module     = m_pixelId->eta_module(id);
-
-	    ATH_MSG_DEBUG("hashId "<<*oit<<"for rodID "<<MSG::hex<<val<<MSG::dec
-			  << "corresponds to b/ec lay_disk phi eta "<<barrel_ec
-			  << " "<<layer_disk<<" "<<phi_module<<" "<<eta_module);
-	}
+
+      std::vector<IdentifierHash> offlineIdHashList;
+      m_pix_cabling_svc->getOfflineList(offlineIdHashList, m_pix_cabling_svc->getRobId(val));
+      ATH_MSG_DEBUG("Trying m_pix_cabling_svc->getOfflineList(offlineIdHashList, m_pix_cabling_svc->getRobId("<<MSG::hex<<val<<MSG::dec<<"));");
+      for (auto oit = offlineIdHashList.begin(); oit != offlineIdHashList.end(); oit++){
+
+	Identifier id = m_pixelId->wafer_id( *oit );
+	int barrel_ec      = m_pixelId->barrel_ec(id);
+	int layer_disk     = m_pixelId->layer_disk(id);
+	int phi_module     = m_pixelId->phi_module(id);
+	int eta_module     = m_pixelId->eta_module(id);
+
+	ATH_MSG_DEBUG("hashId "<<*oit<<"for rodID "<<MSG::hex<<val<<MSG::dec
+		      << "corresponds to b/ec lay_disk phi eta "<<barrel_ec
+		      << " "<<layer_disk<<" "<<phi_module<<" "<<eta_module);
+      }
     }
 
     m_sct_rodIdlist.clear();
@@ -441,28 +438,27 @@ StatusCode FTKRegionalWrapper::initialize()
       int val;
       str>>std::hex>>val;
       m_sct_rodIdlist.push_back(val);
-      
+
       ATH_MSG_DEBUG("Going to test against the following SCT RODIDs "<< MSG::hex
 		    << val <<MSG::dec);
     }
-    
-  }
 
+  }
 
   return StatusCode::SUCCESS;
 }
 
+
+/*
+* prepare the output structure to store the hits and the other information
+*/
 StatusCode FTKRegionalWrapper::initOutputFile() {
-  /*
-   * prepare the output structure to store the hits and the other information
-   */
 
-  MsgStream log(msgSvc(), name());
-  log << MSG::INFO << "FTKRegionalWrapper::initOutputFile()" << endmsg;
+  ATH_MSG_VERBOSE("FTKRegionalWrapper::initOutputFile()" );
 
 
   // create the output files
-  log << MSG::INFO << "Creating output file: "  << m_outpath << endmsg;
+  ATH_MSG_VERBOSE("Creating output file: "  << m_outpath );
   m_outfile = TFile::Open(m_outpath.c_str(),"recreate");
 
 
@@ -482,20 +478,22 @@ StatusCode FTKRegionalWrapper::initOutputFile() {
   m_evtinfo->Branch("ExtendedLevel1ID",&m_extendedLevel1ID,"ExtendedLevel1ID/i");
   m_evtinfo->Branch("Level1TriggerType",&m_level1TriggerType,"Level1TriggerType/i");
   m_evtinfo->Branch("Level1TriggerInfo",&m_level1TriggerInfo);
-  m_evtinfo->Branch("AverageInteractionsPerCrossing",&m_averageInteractionsPerCrossing,"AverageInteractionsPerCrossing/F");
-  m_evtinfo->Branch("ActualInteractionsPerCrossing",&m_actualInteractionsPerCrossing,"ActualInteractionsPerCrossing/F");  
-
+  m_evtinfo->Branch("AverageInteractionsPerCrossing",
+		    &m_averageInteractionsPerCrossing,
+		    "AverageInteractionsPerCrossing/F");
+  m_evtinfo->Branch("ActualInteractionsPerCrossing",
+		    &m_actualInteractionsPerCrossing,
+		    "ActualInteractionsPerCrossing/F");
 
   // create and populate the TTree
   m_hittree = new TTree("ftkhits","Raw hits for the FTK simulation");
   m_hittree_perplane = new TTree("ftkhits_perplane","Raw hits for the FTK simulation");
-  
 
   if (m_getOffline) {
     m_offline_locX = new std::vector<float>;
     m_offline_locY = new std::vector<float>;
-    m_offline_isPixel = new std::vector<int>;
-    m_offline_isBarrel = new std::vector<int>;
+    m_offline_isPixel = new std::vector<bool>;
+    m_offline_isBarrel = new std::vector<bool>;
     m_offline_layer = new std::vector<int>;
     m_offline_clustID = new std::vector<int>;
     m_offline_trackNumber = new std::vector<int>;
@@ -510,7 +508,7 @@ StatusCode FTKRegionalWrapper::initOutputFile() {
     m_offline_cluster_tree->Branch("offline_is_Barrel",&m_offline_isBarrel);
     m_offline_cluster_tree->Branch("offline_layer",&m_offline_layer);
     m_offline_cluster_tree->Branch("offline_clustID",&m_offline_clustID);
-    
+
     m_offline_cluster_tree->Branch("offline_trackNumber",&m_offline_trackNumber);
     m_offline_cluster_tree->Branch("offline_pt",&m_offline_pt);
     m_offline_cluster_tree->Branch("offline_eta",&m_offline_eta);
@@ -524,31 +522,35 @@ StatusCode FTKRegionalWrapper::initOutputFile() {
   if (m_SaveRawHits) { // Save FTKRawHit data
     m_original_hits = new vector<FTKRawHit>[m_ntowers];
     if (m_SavePerPlane) { m_original_hits_per_plane = new vector<FTKRawHit>*[m_ntowers]; }
-    
+
     for (int ireg=0;ireg!=m_ntowers;++ireg) { // towers loop
       m_hittree->Branch(Form("RawHits%d.",ireg),&m_original_hits[ireg], 32000, 1);
-      
+
       if (m_SavePerPlane) {
-        m_original_hits_per_plane[ireg] = new vector<FTKRawHit>[m_nplanes];
-        for (int iplane=0;iplane!=m_nplanes;++iplane) { // planes loop
-          m_hittree_perplane->Branch(Form("RawHits_t%d_p%d.",ireg,iplane),&m_original_hits_per_plane[ireg][iplane],32000, 1);
-        }
+	m_original_hits_per_plane[ireg] = new vector<FTKRawHit>[m_nplanes];
+	for (int iplane=0;iplane!=m_nplanes;++iplane) { // planes loop
+	  m_hittree_perplane->Branch(Form("RawHits_t%d_p%d.",ireg,iplane),
+				     &m_original_hits_per_plane[ireg][iplane],32000, 1);
+	}
       }
     } // end towers loop
   }
 
   if (m_SaveHits) {
     m_logical_hits = new vector<FTKHit>[m_ntowers];
-    if (m_SavePerPlane) { m_logical_hits_per_plane = new vector<FTKHit>*[m_ntowers]; }
-    
+    if (m_SavePerPlane) {
+	m_logical_hits_per_plane = new vector<FTKHit>*[m_ntowers];
+    }
+
     for (int ireg=0;ireg!=m_ntowers;++ireg) { // towers loop
       m_hittree->Branch(Form("Hits%d.",ireg),&m_logical_hits[ireg], 32000, 1);
 
       if (m_SavePerPlane) {
-        m_logical_hits_per_plane[ireg] = new vector<FTKHit>[m_nplanes];
-        for (int iplane=0;iplane!=m_nplanes;++iplane) { // planes loop
-          m_hittree_perplane->Branch(Form("Hits_t%d_p%d.",ireg,iplane), &m_logical_hits_per_plane[ireg][iplane],32000, 1);
-        }
+	m_logical_hits_per_plane[ireg] = new vector<FTKHit>[m_nplanes];
+	for (int iplane=0;iplane!=m_nplanes;++iplane) { // planes loop
+	  m_hittree_perplane->Branch(Form("Hits_t%d_p%d.",ireg,iplane),
+				     &m_logical_hits_per_plane[ireg][iplane],32000, 1);
+	}
       }
     } // end towers loop
   }
@@ -573,7 +575,7 @@ StatusCode FTKRegionalWrapper::execute()
   for (int ireg=0;ireg!=m_ntowers;++ireg) {
     if (m_SaveRawHits) m_original_hits[ireg].clear();
     if (m_SaveHits) m_logical_hits[ireg].clear();
-    
+
     if (m_SavePerPlane) {
       for (int iplane=0;iplane!=m_nplanes;++iplane) { // planes loop
 	if (m_SaveRawHits) m_original_hits_per_plane[ireg][iplane].clear();
@@ -609,7 +611,7 @@ StatusCode FTKRegionalWrapper::execute()
   m_level1TriggerInfo = datainput->level1TriggerInfo();
   m_extendedLevel1ID = datainput->extendedLevel1ID();
 
-  if (std::find(m_L1ID_to_save.begin(), m_L1ID_to_save.end(), m_level1TriggerType) == m_L1ID_to_save.end() 
+  if (std::find(m_L1ID_to_save.begin(), m_L1ID_to_save.end(), m_level1TriggerType) == m_L1ID_to_save.end()
       && m_L1ID_to_save.size() != 0)
     return StatusCode::SUCCESS;
 
@@ -619,7 +621,8 @@ StatusCode FTKRegionalWrapper::execute()
 
   bool dumpedSCT = false;
 
-  //if DF emulation is requested then first check if hits are in DF Rods before doing clustering or writing to file
+  //if DF emulation is requested then first check if hits are in DF Rods before
+  //doing clustering or writing to file
   if(m_EmulateDF){
 
     //get list of original hits
@@ -630,30 +633,29 @@ StatusCode FTKRegionalWrapper::execute()
 
     for (;ihit!=ihitE;++ihit) { // hit loop
       const FTKRawHit &currawhit = *ihit;
-    
+
       //first get the hit's Module identifier hash
       uint32_t modHash = currawhit.getIdentifierHash();
-      
+
 
       if (currawhit.getIsSCT()){
 
 	ATH_MSG_VERBOSE("Processing SCT hit");
-     	//SCT
-	
+	//SCT
+
 	//then get the corresponding RobId
 	uint32_t robid = m_sct_cablingToolInc->getRobIdFromHash(modHash);
-	
 	if (dumpedSCT == false){
 	  ATH_MSG_VERBOSE("Dumping SCT Rod List ");
-	for (auto its = m_sct_rodIdlist.begin(); its <  m_sct_rodIdlist.end(); ++its)
-	  ATH_MSG_VERBOSE(MSG::hex <<*its<<MSG::dec<< " is in the SCT Rod list");
-	dumpedSCT = true;
+	  for (auto its = m_sct_rodIdlist.begin(); its <  m_sct_rodIdlist.end(); ++its)
+	    ATH_MSG_VERBOSE(MSG::hex <<*its<<MSG::dec<< " is in the SCT Rod list");
+	  dumpedSCT = true;
 	}
 	//then try to find in rob list
 	auto it = find(m_sct_rodIdlist.begin(), m_sct_rodIdlist.end(), robid);
-	
+
 	ATH_MSG_VERBOSE("Trying to find "<< MSG::hex <<robid<<MSG::dec
-		      << "in the DF SCT Rod list");
+			<< "in the DF SCT Rod list");
 
 	//only keep hit if found
 	if (it != m_sct_rodIdlist.end()){
@@ -661,30 +663,30 @@ StatusCode FTKRegionalWrapper::execute()
 	}else{
 	  ATH_MSG_VERBOSE("SCT Module is not in the DF Rod list!");
 	  continue;
-	}	
+	}
       }else if (currawhit.getIsPixel()) {
-	  ATH_MSG_VERBOSE("Processing Pixel hit");
-
-	  //pixel
-	  //need to get the identifier from the hash
-	  Identifier dehashedId = m_pixelId->wafer_id(modHash);
-
-	  //then get the corresponding RobId
-	  uint32_t robid = m_pix_cabling_svc->getRobId(dehashedId);
-	  
-	  //then try to find in rob list
-	  auto it = find(m_pix_rodIdlist.begin(), m_pix_rodIdlist.end(), robid);
-	  
-	  ATH_MSG_VERBOSE("Trying to find pixel "<< MSG::hex <<robid<<MSG::dec
+	ATH_MSG_VERBOSE("Processing Pixel hit");
+
+	//pixel
+	//need to get the identifier from the hash
+	Identifier dehashedId = m_pixelId->wafer_id(modHash);
+
+	//then get the corresponding RobId
+	uint32_t robid = m_pix_cabling_svc->getRobId(dehashedId);
+
+	//then try to find in rob list
+	auto it = find(m_pix_rodIdlist.begin(), m_pix_rodIdlist.end(), robid);
+
+	ATH_MSG_VERBOSE("Trying to find pixel "<< MSG::hex <<robid<<MSG::dec
 			<< "in the DF Rod list from "<<dehashedId);
-	  //only keep hit if found
-	  if (it != m_pix_rodIdlist.end()){
-	    ATH_MSG_VERBOSE("Found the Pixel module in the DF Rod list!");
-	  }else{
-	    ATH_MSG_VERBOSE("Pixel Module is not in the DF Rod list!");
-	    continue;
-	  }
-	  
+	//only keep hit if found
+	if (it != m_pix_rodIdlist.end()){
+	  ATH_MSG_VERBOSE("Found the Pixel module in the DF Rod list!");
+	}else{
+	  ATH_MSG_VERBOSE("Pixel Module is not in the DF Rod list!");
+	  continue;
+	}
+
       }else{
 	//this shouldn't happen, so throw error
 	ATH_MSG_ERROR("Hit is neither Pixel or SCT!!");
@@ -698,12 +700,12 @@ StatusCode FTKRegionalWrapper::execute()
     //if no DF emulation, just copy the hits as originally intended
     fulllist = datainput->getOriginalHits();
   }
-  
+
   ATH_MSG_VERBOSE("Going to run  on "<< fulllist.size()<<" hits");
 
   // if the clustering is requested it has to be done before the hits are distributed
   if (m_Clustering ) {
-    atlClusteringLNF(fulllist);
+    m_clusteringEngine->atlClusteringLNF(fulllist);
     vector<FTKRawHit>::iterator ihit = fulllist.begin();
     vector<FTKRawHit>::iterator ihitE = fulllist.end();
     for (;ihit!=ihitE;++ihit) { // hit loop
@@ -712,19 +714,19 @@ StatusCode FTKRegionalWrapper::execute()
       // now we add truth info back in since we did clustering here!
       MultiTruth mt;
       if( currawhit.getTruth() ) {
-        mt.maximize( *(currawhit.getTruth()));
+	mt.maximize( *(currawhit.getTruth()));
       } else {
 	MultiTruth::Barcode uniquecode(currawhit.getEventIndex(),
-                                       currawhit.getBarcode());
-        mt.maximize(uniquecode,currawhit.getBarcodePt());
+				       currawhit.getBarcode());
+	mt.maximize(uniquecode,currawhit.getBarcodePt());
       }
       MultiTruth::Barcode tbarcode;
       MultiTruth::Weight tfrac;
       const bool ok = mt.best(tbarcode,tfrac);
       Int_t index(-1), barcode(0);
       if( ok ) {
-        index = tbarcode.first;
-        barcode = tbarcode.second;
+	index = tbarcode.first;
+	barcode = tbarcode.second;
       }
       currawhit.setEventIndex(index);
       currawhit.setBarcode(barcode);
@@ -762,7 +764,7 @@ StatusCode FTKRegionalWrapper::execute()
 	  continue;
 	}
 	for (; it!=it_end; it++) {
-	  const Trk::TrackStateOnSurface* tsos=(*it);       
+	  const Trk::TrackStateOnSurface* tsos=(*it);
 	  if (tsos == 0) continue;
 	  if ((*it)->type(Trk::TrackStateOnSurface::Measurement) ){
 	    const Trk::MeasurementBase *measurement = (*it)->measurementOnTrack();
@@ -774,7 +776,7 @@ StatusCode FTKRegionalWrapper::execute()
 	      const Identifier & hitId = hit->identify();
 
 	      if (m_idHelper->is_pixel(hitId)) {
-		m_offline_isPixel->push_back(1);
+		m_offline_isPixel->push_back(true);
 		m_offline_isBarrel->push_back(int(m_pixelId->is_barrel(hitId)));
 		const InDetDD::SiDetectorElement* sielement = m_PIX_mgr->getDetectorElement(hitId);
 		m_offline_clustID->push_back(sielement->identifyHash());
@@ -804,39 +806,39 @@ StatusCode FTKRegionalWrapper::execute()
 
   //get all the containers to write clusters
   if(m_WriteClustersToESD){
-    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkSctTruthName)) { 
-      m_ftkSctTruth = new PRD_MultiTruthCollection;
-      
-      StatusCode sc=m_storeGate->record(m_ftkSctTruth,m_ftkSctTruthName,false); 
-      if(sc.isFailure()) { 
-	ATH_MSG_WARNING("SCT FTK Truth Container " << m_ftkSctTruthName  
-			<<" cannot be re-recorded in StoreGate !"); 
+    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkSctTruthName)) {
+	m_ftkSctTruth = std::make_unique<PRD_MultiTruthCollection>();
+
+	StatusCode sc=m_storeGate->record(m_ftkSctTruth.get(),m_ftkSctTruthName,false);
+      if(sc.isFailure()) {
+	ATH_MSG_WARNING("SCT FTK Truth Container " << m_ftkSctTruthName
+			<<" cannot be re-recorded in StoreGate !");
       }
-    } 
-    
-    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkPixelTruthName)) { 
-      m_ftkPixelTruth = new PRD_MultiTruthCollection;
-      
-      StatusCode sc=m_storeGate->record(m_ftkPixelTruth,m_ftkPixelTruthName,false); 
-      if(sc.isFailure()) { 
-	ATH_MSG_WARNING("SCT FTK Truth Container " << m_ftkPixelTruthName  
-			<<" cannot be re-recorded in StoreGate !"); 
-      } 
-    }   
-    
-    
+    }
+
+    if(!m_storeGate->contains<PRD_MultiTruthCollection>(m_ftkPixelTruthName)) {
+	m_ftkPixelTruth = std::make_unique<PRD_MultiTruthCollection>();
+
+	StatusCode sc=m_storeGate->record(m_ftkPixelTruth.get(),m_ftkPixelTruthName,false);
+      if(sc.isFailure()) {
+	ATH_MSG_WARNING("SCT FTK Truth Container " << m_ftkPixelTruthName
+			<<" cannot be re-recorded in StoreGate !");
+      }
+    }
+
+
     // Check the FTK pixel container
     if (!m_storeGate->contains<InDet::PixelClusterContainer>(m_FTKPxlClu_CollName)) {
       m_FTKPxlCluContainer->cleanup();
-      if (m_storeGate->record(m_FTKPxlCluContainer,m_FTKPxlClu_CollName,false).isFailure()) {
+      if (m_storeGate->record(m_FTKPxlCluContainer.get() ,m_FTKPxlClu_CollName,false).isFailure()) {
 	return StatusCode::FAILURE;
       }
     }
-    
+
     // check the FTK SCT container
     if (!m_storeGate->contains<InDet::SCT_ClusterContainer>(m_FTKSCTClu_CollName)) {
       m_FTKSCTCluContainer->cleanup();
-      if (m_storeGate->record(m_FTKSCTCluContainer,m_FTKSCTClu_CollName,false).isFailure()) {
+      if (m_storeGate->record(m_FTKSCTCluContainer.get(), m_FTKSCTClu_CollName,false).isFailure()) {
 	return StatusCode::FAILURE;
       }
     }
@@ -856,18 +858,18 @@ StatusCode FTKRegionalWrapper::execute()
       // In the ITk geometry, some of the plane IDs are -1 if the layers are not yet being used.
       // This causes the code in this hit loop to crash. As a workaround for the moment, we currently
       // skip over hits in layers that are not included in the FTK geometry, with plane = -1
-      if( m_pmap->getMap( currawhit.getHitType() , !(currawhit.getBarrelEC()==0) , currawhit.getLayer() ).getPlane() == -1 )
+      if( m_pmap->getMap( currawhit.getHitType(), !(currawhit.getBarrelEC()==0),
+			  currawhit.getLayer() ).getPlane() == -1 )
 	continue;
     }
-    
-    //cout << "Hit " << currawhit.getHitType() << ": " << currawhit.getEventIndex() << " " << currawhit.getBarcode() << endl;
+
     // calculate the equivalent hit
-    FTKHit hitref = currawhit.getFTKHit(m_pmap);
-    if (m_Clustering ) {		
+    FTKHit hitref = currawhit.getFTKHit(m_pmap.get());
+    if (m_Clustering ) {
       assert(currawhit.getTruth());
       hitref.setTruth(*(currawhit.getTruth()));
     }
-    
+
     if(m_WriteClustersToESD){
       int dim = hitref.getDim();
       switch (dim) {
@@ -876,29 +878,48 @@ StatusCode FTKRegionalWrapper::execute()
       }
 	break;
       case 1: {
-	InDet::SCT_Cluster* pSctCL = m_clusterConverterTool->createSCT_Cluster(hitref.getIdentifierHash(), hitref.getCoord(0), hitref.getNStrips() ); //createSCT_Cluster(h);
-
-	if(pSctCL!=NULL) {
-	  InDet::SCT_ClusterCollection* pColl = m_clusterConverterTool->getCollection(m_FTKSCTCluContainer, hitref.getIdentifierHash());
-	  if(pColl!=NULL) {
-	    pSctCL->setHashAndIndex(pColl->identifyHash(), pColl->size()); 
-	    pColl->push_back(pSctCL); 
+	InDet::SCT_Cluster* pSctCL = m_clusterConverterTool->createSCT_Cluster(hitref.getIdentifierHash(),
+									       hitref.getCoord(0),
+									       hitref.getNStrips() ); //createSCT_Cluster(h);
+
+	if(pSctCL!=nullptr) {
+	    InDet::SCT_ClusterCollection* pColl = m_clusterConverterTool->getCollection(m_FTKSCTCluContainer.get(),
+										      hitref.getIdentifierHash());
+	  if(pColl!=nullptr) {
+	    pSctCL->setHashAndIndex(pColl->identifyHash(), pColl->size());
+	    pColl->push_back(pSctCL);
 	    const MultiTruth& t = hitref.getTruth();
-	    m_clusterConverterTool->createSCT_Truth(pSctCL->identify(), t, m_ftkSctTruth, m_mcEventCollection, m_storeGate, m_mcTruthName);
+	    m_clusterConverterTool->createSCT_Truth(pSctCL->identify(),
+						    t,
+						    m_ftkSctTruth.get(),
+						    m_mcEventCollection,
+						    m_storeGate,
+						    m_mcTruthName);
 	  }
 	}
       }
-	break; 
+	break;
       case 2: {
-	InDet::PixelCluster* pPixCL = m_clusterConverterTool->createPixelCluster(hitref.getIdentifierHash(), hitref.getCoord(0), hitref.getCoord(1), hitref.getEtaWidth(), hitref.getPhiWidth(), hitref.getCoord(1)); //need to fix trkPerigee->eta());
-	
-	if(pPixCL!=NULL) {
-	  InDet::PixelClusterCollection* pColl = m_clusterConverterTool->getCollection(m_FTKPxlCluContainer, hitref.getIdentifierHash());
-	  if(pColl!=NULL) {
-	    pPixCL->setHashAndIndex(pColl->identifyHash(), pColl->size()); 
-	    pColl->push_back(pPixCL); 
+	InDet::PixelCluster* pPixCL = m_clusterConverterTool->createPixelCluster(hitref.getIdentifierHash(),
+										 hitref.getCoord(0),
+										 hitref.getCoord(1),
+										 hitref.getEtaWidth(),
+										 hitref.getPhiWidth(),
+										 hitref.getCoord(1)); //need to fix trkPerigee->eta());
+
+	if(pPixCL!=nullptr) {
+	    InDet::PixelClusterCollection* pColl = m_clusterConverterTool->getCollection(m_FTKPxlCluContainer.get(),
+										       hitref.getIdentifierHash());
+	  if(pColl!=nullptr) {
+	    pPixCL->setHashAndIndex(pColl->identifyHash(), pColl->size());
+	    pColl->push_back(pPixCL);
 	    const MultiTruth& t = hitref.getTruth();
-	    m_clusterConverterTool->createPixelTruth(pPixCL->identify(), t, m_ftkPixelTruth, m_mcEventCollection, m_storeGate, m_mcTruthName);
+	    m_clusterConverterTool->createPixelTruth(pPixCL->identify(),
+						     t,
+						     m_ftkPixelTruth.get(),
+						     m_mcEventCollection,
+						     m_storeGate,
+						     m_mcTruthName);
 	  }
 	}
       }
@@ -909,16 +930,18 @@ StatusCode FTKRegionalWrapper::execute()
 
     // get plane id
     const int plane = hitref.getPlane();
-    
+
     // check the region
     for (int ireg=0;ireg!=m_ntowers;++ireg) {
-      
+
       if (m_rmap->isHitInRegion(hitref,ireg)) {
-        // if the equivalent hit is compatible with this tower the hit is saved
-        if (m_SaveRawHits) m_original_hits[ireg].push_back(currawhit);
-        if (m_SaveHits) m_logical_hits[ireg].push_back(hitref);
+	// if the equivalent hit is compatible with this tower the hit is saved
+	if (m_SaveRawHits)
+	    m_original_hits[ireg].push_back(currawhit);
+	if (m_SaveHits)
+	    m_logical_hits[ireg].push_back(hitref);
 
-        if (m_SavePerPlane) {
+	if (m_SavePerPlane) {
 	  if (m_SaveRawHits)
 	    m_original_hits_per_plane[ireg][plane].push_back(currawhit);
 	  if (m_SaveHits)
@@ -927,15 +950,14 @@ StatusCode FTKRegionalWrapper::execute()
       }
     }
   } // end hit loop
-  
 
-  // fill the branches
+    // fill the branches
   m_hittree->Fill();
 
   if (m_getOffline) m_offline_cluster_tree->Fill();
 
   if (m_SavePerPlane) { m_hittree_perplane->Fill(); }
-  
+
   // get the list of the truth tracks
   m_truth_tracks.clear();
   const vector<FTKTruthTrack> &truthtracks = datainput->getTruthTrack();
@@ -943,8 +965,8 @@ StatusCode FTKRegionalWrapper::execute()
   // Write the tracks
   m_trackstree->Fill();
   if (m_DumpTestVectors) {
-      // Dumps the data, needed to be placed here in order to make sure that StoreGateSvc has loaded
-      dumpFTKTestVectors(m_pmap,m_rmap);
+    // Dumps the data, needed to be placed here in order to make sure that StoreGateSvc has loaded
+      dumpFTKTestVectors(m_pmap.get(), m_rmap.get());
   }
 
   return StatusCode::SUCCESS;
@@ -953,233 +975,235 @@ StatusCode FTKRegionalWrapper::execute()
 //--------------------------------------------------------------------------------------------------------------------------
 // ------- Added by Jean----------------------------------------------------------------------------------------------------
 
-bool FTKRegionalWrapper::dumpFTKTestVectors(FTKPlaneMap *pmap, FTKRegionMap *rmap)
+bool FTKRegionalWrapper::dumpFTKTestVectors(const FTKPlaneMap *pmap, const FTKRegionMap *rmap)
 {
-    MsgStream log(msgSvc(), name());   
-
-   // Some dummy loop variables
-    uint64_t onlineId ;
-    IdentifierHash hashId;
-    Identifier id;
-
-    stringstream ss ; 
-    int hitTyp;
-    //------------------------ Do PIXEL RODIDs first ------------------------------
-    // Note PIXEL RODs are input
-    hitTyp = 1; // pixel
-
-    for (uint32_t rod : m_pix_rodIdlist) {
-
-      // Create file for output, format: LUT_0xABCDFGH.txt
-      ss << "LUT_";
-      ss.setf(ios::showbase); 
-      ss << hex << rod;
-      ss.unsetf(ios::showbase);
-      ss << ".txt";
-      ofstream myfile(ss.str() );
-      myfile.setf(ios::right | ios::showbase);
-
-      if ( myfile.is_open() ) {
-	for (int link = 0; link < 128;link++){   // Loop over all modules
-	    // Retrieve onlineId = link+ROD
-	    onlineId  = m_pix_cabling_svc->getOnlineIdFromRobId(rod,link) ;
-	    hashId   = m_pix_cabling_svc->getOfflineIdHash(onlineId);
-
-	    if (hashId <=999999){ // Adjust for correct output format incase of invalid hashId // TODO: add a proper cutoff!
-
-	        id = m_pixelId->wafer_id( hashId );
-		int barrel_ec      = m_pixelId->barrel_ec(id);
-		int layer_disk     = m_pixelId->layer_disk(id);
-		int phi_module     = m_pixelId->phi_module(id);
-		int eta_module     = m_pixelId->eta_module(id);
-		int eta_module_min = m_pixelId->eta_module_min(id);
-		int eta_module_max = m_pixelId->eta_module_max(id);
-		int eta_index      = m_pixelId->eta_index(id);
-		int eta_index_max  = m_pixelId->eta_index_max(id);
-
-		// Get Plane information
-                FTKPlaneSection &pinfo =  pmap->getMap(hitTyp,!(barrel_ec==0),layer_disk);
-
-		// Get tower information
-	        FTKRawHit dummy;
-
-	        dummy.setBarrelEC(barrel_ec);
-	        dummy.setLayer(layer_disk);
-	        dummy.setPhiModule(phi_module);
-	        dummy.setEtaModule(eta_module);
-
-		stringstream towerList;
-	        FTKHit hitref = dummy.getFTKHit(pmap);
-		int nTowers = 0;
-		int towerId;
-	        for (towerId = 0; towerId<64;towerId++){ // Loop over all 64 eta-phi towers
-	             if (rmap->isHitInRegion(hitref,towerId)){
-		       towerList << towerId << ", ";
-		       nTowers++;
-		     }
-		}
-		
-
-		// Dump data to file:  
-	        // Comment out lines below to adjust output (
-		// Linknumber | OnlineID | HashID | Plane | #Towers| TowerList|
-		 myfile << dec   << setprecision(4) << link  << '\t'
-	                << hex   << onlineId                   << '\t'
-			<< dec   << hashId                     << '\t'
-	                << dec   << pinfo.getPlane()           << '\t'
-                        << dec   << nTowers                    << '\t'; 
-		      
-
-		 // Dump TowerList
-                myfile.unsetf(ios::right | ios::showbase);
-		myfile << setw(20)  << towerList.str() << '\t';
-		towerList.str( string() ) ;
-
-	        myfile.setf(ios::right | ios::showbase);
-	          
-	        // Dump the extend table
-	        myfile << "#"                                 << '\t' 
-		       << hitTyp                            << '\t'
-		       << barrel_ec                           << '\t'
-                       << layer_disk                          << '\t'
-                       << phi_module                          << '\t'
-                       << eta_module                          << '\t'
-                       << eta_module_min                      << '\t'
-                       << eta_module_max                      << '\t'
-                       << eta_index                           << '\t'
-                       << eta_index_max                       << '\t'
-		       << endl;      
-
+  // Some dummy loop variables
+  uint64_t onlineId ;
+  IdentifierHash hashId;
+  Identifier id;
+
+  stringstream ss ;
+  int hitTyp;
+  //------------------------ Do PIXEL RODIDs first ------------------------------
+  // Note PIXEL RODs are input
+  vector<uint32_t>::iterator rodit = m_pix_rodIdlist.begin();
+  vector<uint32_t>::iterator rodit_e = m_pix_rodIdlist.end();
+  hitTyp = 1; // pixel
+
+  for (; rodit!=rodit_e; rodit++){
+
+    // Create file for output, format: LUT_0xABCDFGH.txt
+    ss << "LUT_";
+    ss.setf(ios::showbase);
+    ss << hex << *rodit;
+    ss.unsetf(ios::showbase);
+    ss << ".txt";
+    ofstream myfile(ss.str() );
+    myfile.setf(ios::right | ios::showbase);
+
+    if ( myfile.is_open() ) {
+      for (int link = 0; link < 128;link++){   // Loop over all modules
+	// Retrieve onlineId = link+ROD
+	onlineId  = m_pix_cabling_svc->getOnlineIdFromRobId((*rodit),link) ;
+	hashId   = m_pix_cabling_svc->getOfflineIdHash(onlineId);
+
+	if (hashId <=999999){ // Adjust for correct output format incase of invalid hashId // TODO: add a proper cutoff!
+
+	  id = m_pixelId->wafer_id( hashId );
+	  int barrel_ec      = m_pixelId->barrel_ec(id);
+	  int layer_disk     = m_pixelId->layer_disk(id);
+	  int phi_module     = m_pixelId->phi_module(id);
+	  int eta_module     = m_pixelId->eta_module(id);
+	  int eta_module_min = m_pixelId->eta_module_min(id);
+	  int eta_module_max = m_pixelId->eta_module_max(id);
+	  int eta_index      = m_pixelId->eta_index(id);
+	  int eta_index_max  = m_pixelId->eta_index_max(id);
+
+	  // Get Plane information
+	  FTKPlaneSection &pinfo =  pmap->getMap(hitTyp,!(barrel_ec==0),layer_disk);
+
+	  // Get tower information
+	  FTKRawHit dummy;
+
+	  dummy.setBarrelEC(barrel_ec);
+	  dummy.setLayer(layer_disk);
+	  dummy.setPhiModule(phi_module);
+	  dummy.setEtaModule(eta_module);
+
+	  stringstream towerList;
+	  FTKHit hitref = dummy.getFTKHit(pmap);
+	  int nTowers = 0;
+	  int towerId;
+	  for (towerId = 0; towerId<64;towerId++){ // Loop over all 64 eta-phi towers
+	    if (rmap->isHitInRegion(hitref,towerId)){
+	      towerList << towerId << ", ";
+	      nTowers++;
 	    }
-            else{
-	      myfile  << '\t' << '\t' << '\t' <<hex << hashId << endl;    // Dump invalid hashId
-	        }
 	  }
-      }
-      else{
-	 log << MSG::ERROR << "Couldn't open file to store online-/offlinehashid" << endmsg;
-	 return false;
-      }
-      // Clear the stringstream and close file
-      ss.str( string() ); 
-      myfile.close();
-    }	  
-    
-// ----------------------------Do SCT rodIds-------------------------------------   
-// Note no input for specific SCT RODs are being used here. 
-// The getAllRods returns all of the rods in the StoreGateSvc
-    hitTyp = 0;
-    vector<uint32_t> sctrods;
-    m_sct_cablingToolInc->getAllRods(sctrods);
-    id = 0;
-
-    for (uint32_t rod : sctrods) {
-      // Create file for output, format: LUT_0xABCDFGH.txt
-      ss << "LUT_";
-      ss.setf(ios::showbase); 
-      ss << hex << rod;
-      ss.unsetf(ios::showbase);
-      ss << ".txt";
-      ofstream myfile(ss.str() );
-      myfile.setf( ios::right | ios::showbase);
-      
-      if (myfile.is_open() ) {
 
-	// Retrive hashlist
-	 m_sct_cablingToolInc->getHashesForRod(m_identifierHashList,rod );
-
-	 // Some dumping variables
-	 vector<IdentifierHash>::const_iterator hashit = m_identifierHashList.begin();
-	 vector<IdentifierHash>::const_iterator hashit_e = m_identifierHashList.end();
-	 SCT_OnlineId  sct_onlineId;
-
-	 for (; hashit != hashit_e; ++hashit){  // TODO: Check for invalid onlineId && hashId numbers (?)
-
-	    // Retrieve OnlineId
-	      sct_onlineId = m_sct_cablingToolInc->getOnlineIdFromHash( *hashit );
-	      if (sct_onlineId.rod()  == rod){ // Check for correct rodId
-
-		myfile.setf(ios::right | ios::showbase);
-		id  = m_sctId->wafer_id( *hashit);
-		  
-	        int barrel_ec      = m_sctId->barrel_ec(id);
-	        int layer_disk     = m_sctId->layer_disk(id);
-	        int phi_module     = m_sctId->phi_module(id);
-	        int phi_module_max = m_sctId->phi_module_max(id);
-	        int eta_module     = m_sctId->eta_module(id)  ;
-	        int eta_module_min = m_sctId->eta_module_min(id)  ;
-	        int eta_module_max = m_sctId->eta_module_max(id)  ;
-		int side           = m_sctId->side(id);
-		int strip          = m_sctId->strip(id);
-
-               // Get  plane information
-		FTKPlaneSection &pinfo =  pmap->getMap(hitTyp,!(barrel_ec==0),layer_disk);
-
-	        // Get tower information
-	        FTKRawHit dummy;
-	        dummy.setBarrelEC(barrel_ec);
-	        dummy.setLayer(layer_disk);
-	        dummy.setPhiModule(phi_module);
-	        dummy.setEtaModule(eta_module);
-
-		stringstream towerList;
-		int towerId;
-		int nTowers = 0;
-	        FTKHit hitref = dummy.getFTKHit(pmap);
-	        for (towerId = 0; towerId<64;towerId++){ // Looping over all 64 eta-phi towers
-	             if (rmap->isHitInRegion(hitref,towerId)){
-		       towerList << towerId << ", ";
-		       nTowers++;
-		     }
-		}
-
-       
-
-	        // Dump data to file:  
-	        // Comment out lines below to adjust output
-		// Linknumber | OnlineID | HashID | Plane | #Towers | TowerList
-		 myfile << dec  <<  sct_onlineId.fibre() << '\t'
-			<< hex  <<  sct_onlineId         << '\t'
-		        << dec  << *hashit                 << '\t'
-	                << dec  << pinfo.getPlane()         << '\t'
-                        << dec  << nTowers                  << '\t';
-
-		 // Dump TowerList
-
-		myfile.unsetf(ios::right | ios::showbase);
-		myfile << setw(20) << towerList.str() << '\t';
-		towerList.str( string() );
-		myfile.setf(ios::right | ios::showbase);
-
-		// Dump Extended table
-		myfile  <<  "#"                            << '\t'
-                        << hitTyp                        << '\t'
-		        << barrel_ec                       << '\t'
-                        << layer_disk                      << '\t'
-                        << phi_module                      << '\t'
-                        << phi_module_max                  << '\t'
-                        << eta_module                      << '\t'
-                        << eta_module_min                  << '\t'
-                        << eta_module_max                  << '\t'
-                        << side                            << '\t'
-                        << strip                           << '\t'
-	                << endl;  
-	      }
-	 }
-      
+
+	  // Dump data to file:
+	  // Comment out lines below to adjust output (
+	  // Linknumber | OnlineID | HashID | Plane | #Towers| TowerList|
+	  myfile << dec   << setprecision(4) << link  << '\t'
+		 << hex   << onlineId                   << '\t'
+		 << dec   << hashId                     << '\t'
+		 << dec   << pinfo.getPlane()           << '\t'
+		 << dec   << nTowers                    << '\t';
+
+
+	  // Dump TowerList
+	  myfile.unsetf(ios::right | ios::showbase);
+	  myfile << setw(20)  << towerList.str() << '\t';
+	  towerList.str( string() ) ;
+
+	  myfile.setf(ios::right | ios::showbase);
+
+	  // Dump the extend table
+	  myfile << "#"                                 << '\t'
+		 << hitTyp                            << '\t'
+		 << barrel_ec                           << '\t'
+		 << layer_disk                          << '\t'
+		 << phi_module                          << '\t'
+		 << eta_module                          << '\t'
+		 << eta_module_min                      << '\t'
+		 << eta_module_max                      << '\t'
+		 << eta_index                           << '\t'
+		 << eta_index_max                       << '\t'
+		 << endl;
+
+	}
+	else{
+	  myfile  << '\t' << '\t' << '\t' <<hex << hashId << endl;    // Dump invalid hashId
+	}
       }
-      else {
-	log << MSG::ERROR << "Couldn't open file to store online-/offlinehashid" << endmsg;
-	 return false;
+    }
+    else{
+      ATH_MSG_ERROR("Couldn't open file to store online-/offlinehashid" );
+      return false;
+    }
+    // Clear the stringstream and close file
+    ss.str( string() );
+    myfile.close();
+  }
+
+  // ----------------------------Do SCT rodIds-------------------------------------
+  // Note no input for specific SCT RODs are being used here.
+  // The getAllRods returns all of the rods in the StoreGateSvc
+  hitTyp = 0;
+  vector<uint32_t> sctrods;
+  m_sct_cablingToolInc->getAllRods(sctrods);
+  vector<uint32_t>::iterator sctrodit = sctrods.begin();
+  vector<uint32_t>::iterator sctrodit_e = sctrods.end();
+  id = 0;
+
+  for (; sctrodit != sctrodit_e ; sctrodit++){
+    // Create file for output, format: LUT_0xABCDFGH.txt
+    ss << "LUT_";
+    ss.setf(ios::showbase);
+    ss << hex << *sctrodit;
+    ss.unsetf(ios::showbase);
+    ss << ".txt";
+    ofstream myfile(ss.str() );
+    myfile.setf( ios::right | ios::showbase);
+
+    if (myfile.is_open() ) {
+
+      // Retrive hashlist
+      m_sct_cablingToolInc->getHashesForRod(m_identifierHashList,*sctrodit );
+
+      // Some dumping variables
+      vector<IdentifierHash>::const_iterator hashit = m_identifierHashList.begin();
+      vector<IdentifierHash>::const_iterator hashit_e = m_identifierHashList.end();
+      SCT_OnlineId  sct_onlineId;
+
+      for (; hashit != hashit_e; ++hashit){  // TODO: Check for invalid onlineId && hashId numbers (?)
+
+	// Retrieve OnlineId
+	sct_onlineId = m_sct_cablingToolInc->getOnlineIdFromHash( *hashit );
+	if (sct_onlineId.rod()  == (*sctrodit)){ // Check for correct rodId
+
+	  myfile.setf(ios::right | ios::showbase);
+	  id  = m_sctId->wafer_id( *hashit);
+
+	  int barrel_ec      = m_sctId->barrel_ec(id);
+	  int layer_disk     = m_sctId->layer_disk(id);
+	  int phi_module     = m_sctId->phi_module(id);
+	  int phi_module_max = m_sctId->phi_module_max(id);
+	  int eta_module     = m_sctId->eta_module(id)  ;
+	  int eta_module_min = m_sctId->eta_module_min(id)  ;
+	  int eta_module_max = m_sctId->eta_module_max(id)  ;
+	  int side           = m_sctId->side(id);
+	  int strip          = m_sctId->strip(id);
+
+	  // Get  plane information
+	  FTKPlaneSection &pinfo =  pmap->getMap(hitTyp,!(barrel_ec==0),layer_disk);
+
+	  // Get tower information
+	  FTKRawHit dummy;
+	  dummy.setBarrelEC(barrel_ec);
+	  dummy.setLayer(layer_disk);
+	  dummy.setPhiModule(phi_module);
+	  dummy.setEtaModule(eta_module);
+
+	  stringstream towerList;
+	  int towerId;
+	  int nTowers = 0;
+	  FTKHit hitref = dummy.getFTKHit(pmap);
+	  for (towerId = 0; towerId<64;towerId++){ // Looping over all 64 eta-phi towers
+	    if (rmap->isHitInRegion(hitref,towerId)){
+	      towerList << towerId << ", ";
+	      nTowers++;
+	    }
+	  }
+
+
+
+	  // Dump data to file:
+	  // Comment out lines below to adjust output
+	  // Linknumber | OnlineID | HashID | Plane | #Towers | TowerList
+	  myfile << dec  <<  sct_onlineId.fibre() << '\t'
+		 << hex  <<  sct_onlineId         << '\t'
+		 << dec  << *hashit                 << '\t'
+		 << dec  << pinfo.getPlane()         << '\t'
+		 << dec  << nTowers                  << '\t';
+
+	  // Dump TowerList
+
+	  myfile.unsetf(ios::right | ios::showbase);
+	  myfile << setw(20) << towerList.str() << '\t';
+	  towerList.str( string() );
+	  myfile.setf(ios::right | ios::showbase);
+
+	  // Dump Extended table
+	  myfile  <<  "#"                            << '\t'
+		  << hitTyp                        << '\t'
+		  << barrel_ec                       << '\t'
+		  << layer_disk                      << '\t'
+		  << phi_module                      << '\t'
+		  << phi_module_max                  << '\t'
+		  << eta_module                      << '\t'
+		  << eta_module_min                  << '\t'
+		  << eta_module_max                  << '\t'
+		  << side                            << '\t'
+		  << strip                           << '\t'
+		  << endl;
 	}
-      // Clear the stringstream and close file
-      ss.str( string() ); 
-      myfile.close();
+      }
+
     }
+    else {
+      ATH_MSG_ERROR("Couldn't open file to store online-/offlinehashid" );
+      return false;
+    }
+    // Clear the stringstream and close file
+    ss.str( string() );
+    myfile.close();
+  }
+
+  ATH_MSG_INFO("Dumped FTKTestvectors" );
+  return true;
 
-    log << MSG::INFO << "Dumped FTKTestvectors" << endmsg;
-    return true;
-    
 }
 //--------------------------------------------------------------------------------------------------------------------------
 //--------------------------------------------------------------------------------------------------------------------------
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKBankGenAlgo.h b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKBankGenAlgo.h
index 3ec1b23d8e4b..2fcdfc0fc0b4 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKBankGenAlgo.h
+++ b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKBankGenAlgo.h
@@ -126,6 +126,7 @@ private:
   
   std::string m_sector_dir_path;//for const test
   std::string m_gcon_dir_path;//for const test
+
   char m_c_sector_dir_path[200];
   char m_c_gcon_dir_path[200];
 
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKConstGenAlgo.h b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKConstGenAlgo.h
index 629a88a61428..e3966bc57f3b 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKConstGenAlgo.h
+++ b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKConstGenAlgo.h
@@ -68,6 +68,7 @@ public:
   std::string m_extractpath;  
   
   std::string m_outfilename; // the algorithm mostly produce a single file, if set this is the name of the file, a default option is otherwise used
+  TFile *m_file;
   TFile *m_good_file;
   TFile *m_cfile;
   TTree *m_ctree;
@@ -80,9 +81,12 @@ public:
   int m_nfile;
   int m_addPattReturnCode;
   float m_nsector;
+  bool m_match;
  
   double m_pr;
 
+  int m_nevent;
+
   int m_nplane;
   int m_nplane8;
 
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h
new file mode 100644
index 000000000000..7da2c085c50b
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h
@@ -0,0 +1,43 @@
+#ifndef FTKDataMatrixFromMCAlgo_h
+#define FTKDataMatrixFromMCAlgo_h
+
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "TrigFTKSim/FTKLogging.h"
+#include "TrigFTKBankGen/FTKGhostHitCalculator.h"
+
+#include <TFile.h>
+#include <string>
+
+class FTKDataMatrixFromMCAlgo : public AthAlgorithm, public FTKLogger {
+public:
+   FTKDataMatrixFromMCAlgo(const std::string& name, ISvcLocator* pSvcLocator);
+   virtual ~FTKDataMatrixFromMCAlgo ();
+   StatusCode initialize();
+   StatusCode execute();
+   StatusCode finalize();
+ protected:
+   virtual void PostMessage(void); // divert FTKLogger messages to Athena
+   std::string m_MCmatrixFileName;
+   std::string m_DATAmatrixFileName;
+   std::string m_debugFileName;
+   std::string m_MCmodulePositionFileName;
+   std::string m_DATAmodulePositionFileName;
+   std::string m_pmap_path;
+   std::string m_rmap_path;
+   int m_HWMODEID;
+   int m_tower;
+   int m_invertIBLphiMatrix;
+   int m_invertIBLphiData;
+   std::string m_modulelut_path;
+   double m_matrixVtxX,m_matrixVtxY,m_matrixVtxZ;
+   double m_dataVtxX,m_dataVtxY,m_dataVtxZ;
+   
+   FTKRegionMap *m_rmap;
+   FTKGhostHitCalculator *m_MCmodulePositionCalculator;
+   FTKGhostHitCalculator *m_DATAmodulePositionCalculator;
+   TFile *m_MCmatrixFile; // input: FTK matrix file for MC geometry
+   TFile *m_DATAmatrixFile; // output: FTK matrix file for data geometry
+   TFile *m_debugFile;
+};
+
+#endif
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKGhostHitCalculator.h b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKGhostHitCalculator.h
new file mode 100644
index 000000000000..c0b66a06d461
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKBankGen/TrigFTKBankGen/FTKGhostHitCalculator.h
@@ -0,0 +1,143 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef FTKGHOSTHITCALCULATOR_H
+#define FTKGHOSTHITCALCULATOR_H
+
+/* class FTKGhostHitCalculator
+ *
+ * extrapolate truth tracks to dead modules and estimate ghost hit positions
+ *
+ * the mapping of modules to FTK planes and towers is defined by
+ * the method setFTKGeometry()
+ *
+ * the module positions are read from a TTree loadModuleGeometry()
+ * in that three, dead modules are defined
+ * overwrite the dead module positions using
+ *   clearBadModuleList() and  addBadModules()
+ *
+ * for a given module ID, check whether the module is on the "bad" list
+ *    isBad()
+ *
+ * for a given truth track, module positions are added
+ *    using the method addGhostHit()
+ *
+ * Author: Stefan Schmitt, DESY
+ * Date: 2017/06/28
+ *
+ */
+
+#include "TrigFTKSim/FTKLogging.h"
+#include <TVector3.h>
+#include <TVector2.h>
+#include <vector>
+#include <map>
+#include <set>
+
+class FTKRegionMap;
+class FTKTruthTrack;
+class TDirectory;
+class FTKHit;
+
+struct FTK_ModuleGeometry {
+   // geometry data of a single module
+   int m_isPixel;
+   int m_id;
+   int m_plane;
+   int m_hitSector;
+   TVector3 m_center;
+   TVector3 m_phiAxis;
+   TVector3 m_etaAxis;
+   TVector2 m_pitch;
+   TVector2 m_width;
+   // extrapolation method
+   bool extrapolate(double rho,double cotTh,double z0,double d0,
+                    double sinPhi0,double cosPhi0,TVector3 const *trackVertex,
+                    double *xLocPtr,TVector2 *xPtr,double *sPtr) const;
+};
+
+class FTK_ModuleLocator {
+ public:
+   // locate a module
+   //
+   // for barrel geometry,
+   //    determine R[min,max] order all modules by Z for fast lookup
+   // for endcap geometry,
+   //    determine Z[min,max] order all modules by R for fast lookup
+   // 
+   void insert(FTK_ModuleGeometry const *module);
+   FTKHit *locate(FTKTruthTrack const &track,FTK_ModuleGeometry *module=0) const;
+   void print(void) const;
+ protected:
+   struct FTK_ModuleSet {
+      // barrel or disk geometry
+      int m_isBarrel;
+      // m_x: Rmin,Rmax (barrel) Zmin,Zmax (endcap)
+      double m_x[2];
+      // m_dy: maximum module width in Z (Barrel), in R (endcap)
+      double m_dy;
+      // m_modules: modules orderd by Zavg (Barrel), Ravg (Endcap)
+      std::multimap<double,FTK_ModuleGeometry const *> m_modules;
+      // method to intersect track with modules
+      // if a module matches, the intersection and the module
+      // are added to the output
+      // the candidates are ordered by the arc length
+      void getCandidates(double rho,double cotTh,double z0,double d0,
+                         double sinPhi0,double cosPhi0,std::multimap
+                         <double,std::pair<TVector2,FTK_ModuleGeometry
+                         const *> > &candidate) const;
+   };
+   // barrel,endcap have different module sets
+   // also, if R(barrel) or z(endcap) differs too much, start a new set
+   std::vector<FTK_ModuleSet> m_moduleSetVector;
+};
+
+class FTKGhostHitCalculator : public FTKLogging {
+ public:
+   FTKGhostHitCalculator(const FTKRegionMap *rmap,
+                         std::string const &name="FTKGhostHitCalculator");
+   int loadModuleGeometry(std::string const &name,bool markAllBad,bool invertIBLphi);
+   virtual int loadModuleGeometry(TDirectory *source,bool markAllBad,bool invertIBLphi);
+
+   virtual void clearBadModuleList(void);
+   int addBadModules(std::string const &name);
+   int addBadModules(std::istream &in);
+
+   virtual FTKHit *addGhostHit( FTKTruthTrack const &track,int plane,
+                               FTK_ModuleGeometry *module=0 ) const;
+   virtual bool isBad(int plane,int moduleID) const;
+
+   // returns: 
+   //   0: all ok
+   //   1: bad plane number
+   //   2: bad module id
+   //   3: extrapolation failed
+   virtual int extrapolateTo
+      (size_t plane,int moduleID,double rho,double cotTh,double z0,double d0,
+       double sinPhi0,double cosPhi0,TVector3 const *trackVertex,
+       double *x) const;
+   virtual FTK_ModuleGeometry const *findModule(size_t plane,int moduleID) const;
+ protected:
+   int addBadPixelModules(std::set<int> const &bad);
+   int addBadSCTModules(std::set<int> const &bad);
+
+   void updateCalculator(void);
+
+   FTKRegionMap const *m_rmap;
+
+   // for each module ID give the plane number
+   std::map<int,int> m_planeFromPIXid,m_plane_From_SCTid;
+
+   // bad modules
+   std::set<int> m_badPixel,m_badSCT;
+
+   // give geometry data by plane and module ID
+   // the vector index maps the modules to FTK planes
+   // the map index is the module id
+   std::vector<std::map<int,FTK_ModuleGeometry> > m_geometryData;
+   //
+   // each plane has its own ModuleLocator
+   std::vector<FTK_ModuleLocator> m_moduleLocatorByPlane;
+};
+
+#endif
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKConstantGen.py b/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKConstantGen.py
index 23565cfe4864..3e2d33afad82 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKConstantGen.py
+++ b/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKConstantGen.py
@@ -40,7 +40,6 @@ if not hasattr(runArgs, "ITkMode") :
     setattr(runArgs, "ITkMode", False)
 FTKConstGenAlgo.ITkMode= runArgs.ITkMode
 
-
 if not hasattr(runArgs, "bankregion") :
     setattr(runArgs, "bankregion", 0)
 FTKConstGenAlgo.region=runArgs.bankregion # if the previous option is True this line is not important
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKMatrixReduction.py b/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKMatrixReduction.py
index e8ee908f08c2..16364db26af4 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKMatrixReduction.py
+++ b/Trigger/TrigFTK/TrigFTKBankGen/share/skeleton.FTKMatrixReduction.py
@@ -32,10 +32,13 @@ FTKConstGenAlgo.eightLayer= runArgs.eightLayer
 
 FTKConstGenAlgo.nbank=runArgs.NBanks
 
+<<<<<<< HEAD
 if not hasattr(runArgs, "ITkMode") :
     setattr(runArgs, "ITkMode", False)
 FTKConstGenAlgo.ITkMode= runArgs.ITkMode
 
+=======
+>>>>>>> upstream/21.3
 if not hasattr(runArgs, "allregions") :
     setattr(runArgs, "allregions", False)
 FTKConstGenAlgo.allregion = runArgs.allregions 
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKBankGenAlgo.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKBankGenAlgo.cxx
index 1eb55d22ba66..8cbd3c7f60fb 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKBankGenAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKBankGenAlgo.cxx
@@ -6,7 +6,7 @@
 #include "TrigFTKBankGen/FTKPattKDTree.h"
 #include "TrigFTKSim/FTKSetup.h"
 #include "TrigFTKSim/FTK_SGHitInput.h"
-#include "TrigFTKSim/atlClustering.h"
+#include "TrigFTKSim/FTKClusteringEngine.h"
 
 #include "GaudiKernel/MsgStream.h"
 
@@ -388,12 +388,12 @@ StatusCode FTKBankGenAlgo::initialize(){
       m_tree[i]->Branch("tmpPhi", &m_tmpPhi,"tmpPhi/D");
       m_tree[i]->Branch("tmpCoto", &m_tmpCoto,"tmpCoto/D");
       m_tree[i]->Branch("tmpZ", &m_tmpZ,"tmpZ/D");
-      m_tree[i]->Branch("tmpxC2", m_tmpxC,"tmpxC2[ndim]/D");
-      m_tree[i]->Branch("tmpxD2", m_tmpxD,"tmpxD2[ndim]/D");
-      m_tree[i]->Branch("tmpxPhi2", m_tmpxPhi,"tmpxPhi2[ndim]/D");
-      m_tree[i]->Branch("tmpxCoto2", m_tmpxCoto,"tmpxCoto2[ndim]/D");
-      m_tree[i]->Branch("tmpxZ2", m_tmpxZ,"tmpxZ2[ndim]/D");
-      m_tree[i]->Branch("tmpcovx2", m_tmpcovx,"tmpcovx2[ndim2]/D");
+      m_tree[i]->Branch("tmpxC", m_tmpxC,"tmpxC[ndim]/D");
+      m_tree[i]->Branch("tmpxD", m_tmpxD,"tmpxD[ndim]/D");
+      m_tree[i]->Branch("tmpxPhi", m_tmpxPhi,"tmpxPhi[ndim]/D");
+      m_tree[i]->Branch("tmpxCoto", m_tmpxCoto,"tmpxCoto[ndim]/D");
+      m_tree[i]->Branch("tmpxZ", m_tmpxZ,"tmpxZ[ndim]/D");
+      m_tree[i]->Branch("tmpcovx", m_tmpcovx,"tmpcovx[ndim2]/D");
     
       m_intc= new std::vector<short>;
       m_intphi= new std::vector<short>;
@@ -497,7 +497,6 @@ StatusCode FTKBankGenAlgo::execute() {
       m_trainingtracks.push_back(m_truth_track[i]);
       // prepare the entry in the map of hits
       m_maphits[m_truth_track[i].getBarcode()] = vector<FTKHit>();
-
       m_monval[2]++;
     }
   }
@@ -650,7 +649,7 @@ StatusCode FTKBankGenAlgo::execute() {
                 }
 
                 // sector overlap is a perfectly reasonable situation with forward disks
-                // m_eta and phi will differ in general in this case
+                // eta and phi will differ in general in this case
                 // Take the lower-z hit preferentially (right thing to do? d0/pT tradeoff)
                 // But something fishy is going on if we've got two hits on the same disk.
               }
@@ -761,22 +760,6 @@ StatusCode FTKBankGenAlgo::execute() {
         nregion=-999;
       } else {
 
-        // use sectorID as Identifier Hash
-	/* tkaji
-        if (m_UseIdentifierHash){
-          for(int i=0;i<m_nplanes;++i) {
-            log << MSG::DEBUG << "getsector " <<sechit[i].sector_HW<< endmsg;
-            m_p_ss[i]=sechit[i].sector_HW;
-          }
-        }
-        else {
-          for(int i=0;i<m_nplanes;++i) {
-            log << MSG::DEBUG << "getsector " <<sechit[i].sector<< endmsg;
-            m_p_ss[i]=sechit[i].sector;
-          }
-        }
-	*/
-
 	for(int i=0;i<m_nplanes;i++){
 	  m_p_hashss[i] = sechit[i].sector_HW;
 	  m_p_ss[i] = sechit[i].sector;
@@ -828,7 +811,7 @@ StatusCode FTKBankGenAlgo::execute() {
                   else if (refeta==1&&cureta==2&&sechit[m_nplanes-1].originalhit.getEtaCode()>=6) nregion = itwr;
                 }
                 else {
-                  /* If the the current and reference towers are in the same m_eta
+                  /* If the the current and reference towers are in the same eta
                    * region, the greater index is preferred. The exception is to
                    * consider refphi=0 preferred to curphi=15, to restore the simmetry
                    */
@@ -856,7 +839,7 @@ StatusCode FTKBankGenAlgo::execute() {
                   else if (refeta==1&&cureta==2&&sechit[m_nplanes-1].originalhit.getEtaCode()>=6) nregion = itwr;
                 }
                 else {
-                  /* If the the current and reference towers are in the same m_eta
+                  /* If the the current and reference towers are in the same eta
                    * region, the greater index is preferred. The exception is to
                    * consider refphi=0 preferred to curphi=7, to restore the simmetry
                    */
@@ -892,8 +875,8 @@ StatusCode FTKBankGenAlgo::execute() {
             int phi = sechit[i].sector/1000;
             result[i]=0;
 
-            if(sechit[i].sector%1000<20){//section and m_eta definition
-              //	    if(sechit[i].sector_ref%1000<20){//section and m_eta definition
+            if(sechit[i].sector%1000<20){//section and eta definition
+              //	    if(sechit[i].sector_ref%1000<20){//section and eta definition
               section=0;
             }else{
               section=sechit[i].sector%10;
@@ -953,7 +936,7 @@ StatusCode FTKBankGenAlgo::execute() {
           static int *result_eta;
           static int allocated_eta = 0;
           int region_eta = -1;
-          // total tower id's where we switch tower-m_eta
+          // total tower id's where we switch tower-eta
           const int t0 = 0;
           const int t1 = m_rmap->getNumRegionsPhi()*1;
           const int t2 = m_rmap->getNumRegionsPhi()*2;
@@ -1046,7 +1029,7 @@ StatusCode FTKBankGenAlgo::execute() {
           int tow0_OK;
           int j;
 
-          if(-1 != region_eta){//m_eta is defined
+          if(-1 != region_eta){//eta is defined
             if(!allocated_phi) {
               allocated_phi = 1;
               if((result_phi = (int *)calloc(m_nplanes,sizeof(int))) == NULL)
@@ -1102,7 +1085,7 @@ StatusCode FTKBankGenAlgo::execute() {
               }
             }
 
-          }//m_eta is defined
+          }//eta is defined
 
           /////////////////////
           //  which region?? //
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKCachedBankGenAlgo.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKCachedBankGenAlgo.cxx
index 44dd40b20ce2..11383033dbcc 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKCachedBankGenAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKCachedBankGenAlgo.cxx
@@ -291,6 +291,8 @@ StatusCode FTKCachedBankGenAlgo::RunCachedBankGenerator(){
    FTK_CompressedAMBank bank(m_curreg,m_iSubReg,ssmapAM,ssmapTSP,
                              m_hwmodeid_tspcc,m_hwmodeid_dc);
 
+   bank.setCompressionScheme(FTK_CompressedAMBank::COMPRESSION_DELTA);
+
    if(bank.getHWModeSS_dc() != bank.getHWModeSS_tsp()) {
       if(m_sectordefHW0.empty() || m_sectordefHW2.empty()) {
 	 ATH_MSG_FATAL("Different HWMODEID for TSP and DC bank but sector definition files not given");
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKConstGenAlgo.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKConstGenAlgo.cxx
index 969026c66b00..1c433ed30c5a 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKConstGenAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKConstGenAlgo.cxx
@@ -137,7 +137,7 @@ StatusCode FTKConstGenAlgo::initialize(){
 
     // These 6 counters will evolve in each step of map building
     // to generalize to 1st/2nd stage extrapolation.
-    m_endcap_inversion = new bool[m_nplane];
+    m_endcap_inversion = new bool[12];
 
     m_plane_index_1st_stage = 0;
     m_plane_index_2nd_stage = 0;
@@ -879,7 +879,6 @@ void FTKConstGenAlgo::constantgen()
   maxvals[2]= maxvals[2]*M_PI;
   minvals[2]= minvals[2]*M_PI;
 
-  // Hardcoded resolutions need to be fixed
   double resolutions[14] = {0.04, 0.08265625, 0.04, 0.08265625, 0.04, 0.08265625, 0.04515625, 0.04515625, 0.04515625, 0.04515625, 0.04515625, 0.04515625, 0.04515625, 0.04515625};
 #ifdef DEBUG_NOISE
   float n[30];
@@ -1201,23 +1200,23 @@ void FTKConstGenAlgo::constantgen()
     gco.real = gc.real;
 
     for(int i=0;i<ndim-NPARS;i++) {
-      m_pr = proj(gc.Vd,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
+      m_pr =  proj(gc.Vd,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
       for(int j=0;j<ndim;j++) gco.Vd[j] += -gc.kernel[i][j]*m_pr;
       gco.Cd += -gc.kaverages[i]*m_pr;
       
-      m_pr = proj(gc.Vc,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
+      m_pr =  proj(gc.Vc,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
       for(int j=0;j<ndim;j++) gco.Vc[j] += - gc.kernel[i][j]*m_pr;
       gco.Cc += -gc.kaverages[i]*m_pr;
 	  
-      m_pr = proj(gc.Vf,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
+      m_pr =  proj(gc.Vf,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
       for(int j=0;j<ndim;j++) gco.Vf[j] += -gc.kernel[i][j]*m_pr;
       gco.Cf += -gc.kaverages[i]*m_pr;
 
-      m_pr = proj(gc.Vz0,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
+      m_pr =  proj(gc.Vz0,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
       for(int j=0;j<ndim;j++) gco.Vz0[j] += -gc.kernel[i][j]*m_pr;
       gco.Cz0 += -gc.kaverages[i]*m_pr;
 
-      m_pr = proj(gc.Vo,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
+      m_pr =  proj(gc.Vo,gc.kernel[i],ndim)/proj(gc.kernel[i],gc.kernel[i],ndim);
       for(int j=0;j<ndim;j++) gco.Vo[j] += -gc.kernel[i][j]*m_pr;
       gco.Co += -gc.kaverages[i]*m_pr;
       
@@ -1479,7 +1478,7 @@ void FTKConstGenAlgo::extract_1stStage()
   TTree *slice_tree = (TTree*) Lfile->Get("slice");
 
   for(int idx=0; idx<(int)m_vec_plane_index_2nd_stage.size(); idx++){
-    log << MSG::INFO <<"2nd stage layer :" << m_vec_plane_index_2nd_stage[idx] << ", 1st stage layer: "<< m_vec_plane_index_1st_stage[idx] << ", doInvert: " << m_vec_doInvert[idx] << ", coord 2nd stage: " << m_vec_coord_index_2nd_stage[idx] << ", coord 1st stage: " << m_vec_coord_index_1st_stage[idx] << endmsg;
+    log << MSG::INFO <<"2nd stage layer :" << m_vec_plane_index_2nd_stage[idx] << ", 1st stage layer: "<< m_vec_plane_index_1st_stage[idx] << ", m_doInvert: " << m_vec_doInvert[idx] << ", coord 2nd stage: " << m_vec_coord_index_2nd_stage[idx] << ", coord 1st stage: " << m_vec_coord_index_1st_stage[idx] << endmsg;
   }
 
   // prepare the pointers to retrieve the data from the TTrees
@@ -1505,8 +1504,8 @@ void FTKConstGenAlgo::extract_1stStage()
   double *tmpxZ;
   double *tmpcovx;
 
-  int ndim8 = m_pmap_8L->getTotalDim();
-  int ndim2_8 = ndim8*ndim8;
+  int ndim8 = m_pmap_8L->getTotalDim(); //11;
+  int ndim2_8 = ndim8*ndim8; //11*11;
   int nth_dim8 = 0;
   int nth_dim8_2 = 0;
   int idx_cov8 = 0;
@@ -1649,16 +1648,10 @@ void FTKConstGenAlgo::extract_1stStage()
       Mtmp.Coto=tmpCoto, Mtmp.Z=tmpZ,Mtmp.nhit=nhit;
 
       // check if the module belongs to endcap (for endcap inversion.).
-      std::vector<bool> isEndcap (m_nplane);
+      bool isEndcap[12]={0};
 
       for(int plane_idx_2nd_stage = 0;plane_idx_2nd_stage<m_nplane;plane_idx_2nd_stage++){
-	if(m_ITkMode){
-	  if((sectorID[plane_idx_2nd_stage]%100) / 10 != 2 ){
-	    isEndcap[plane_idx_2nd_stage]=true;
-	  }
-	}else{
-	  if(sectorID[plane_idx_2nd_stage]%1000>20) isEndcap[plane_idx_2nd_stage]=true;
-	}
+      	if(sectorID[plane_idx_2nd_stage]%1000>20) isEndcap[plane_idx_2nd_stage]=true;
       }
 
       // main function extract 1st stage (8L) from 2nd stage (12L)
@@ -1670,9 +1663,9 @@ void FTKConstGenAlgo::extract_1stStage()
 	  if(m_vec_plane_index_2nd_stage[idx_layer] % 2 == 0) m_inversion = 1;
 	  else m_inversion = -1;
 
-	}else{// if no m_inversion
+	}else{// if no inversion
 	  m_inversion = 0;
-	}// endcap m_inversion
+	}// endcap inversion
 
 	sectorID8[idx_layer] = sectorID[m_vec_plane_index_2nd_stage[idx_layer] + m_inversion];
 	hashID8[idx_layer] = hashID[m_vec_plane_index_2nd_stage[idx_layer] + m_inversion];
@@ -1699,9 +1692,9 @@ void FTKConstGenAlgo::extract_1stStage()
 		if(m_vec_plane_index_2nd_stage[idx2_layer] % 2 == 0) m_inversion2 = 1;
 		else m_inversion2 = -1;
 		
-	      }else{// if no m_inversion
+	      }else{// if no inversion
 		m_inversion2 = 0;
-	      }// endcap m_inversion
+	      }// endcap inversion
 
 	      nth_dim2   = m_vec_coord_index_2nd_stage[idx2_layer] + ndm2;
 	      nth_dim8_2 = m_vec_coord_index_1st_stage[idx2_layer] + ndm2;
@@ -1857,11 +1850,11 @@ void FTKConstGenAlgo::extract_1stStage()
     m_extract_intz0= new std::vector<short>;
     m_extract_inteta= new std::vector<short>;
 
-    tree->Branch("tmpintc", &m_extract_intc);
-    tree->Branch("tmpintphi", &m_extract_intphi);
-    tree->Branch("tmpintd0", &m_extract_intd0);
-    tree->Branch("tmpintz0", &m_extract_intz0);
-    tree->Branch("tmpinteta", &m_extract_inteta);
+    mtree->Branch("tmpintc", &m_extract_intc);
+    mtree->Branch("tmpintphi", &m_extract_intphi);
+    mtree->Branch("tmpintd0", &m_extract_intd0);
+    mtree->Branch("tmpintz0", &m_extract_intz0);
+    mtree->Branch("tmpinteta", &m_extract_inteta);
 
     bank_order = b - b_int;
 
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKDataMatrixFromMCAlgo.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKDataMatrixFromMCAlgo.cxx
new file mode 100644
index 000000000000..5674d3d20e46
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKDataMatrixFromMCAlgo.cxx
@@ -0,0 +1,696 @@
+#include "TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h"
+#include "TrigFTKSim/FTKRegionMap.h"
+#include "TrigFTKSim/FTKSetup.h"
+#include <TTree.h>
+#include <TH2F.h>
+#include <TVectorD.h>
+#include <TMatrixD.h>
+#include <TMatrixDSymEigen.h>
+#include <TError.h>
+#include <vector>
+
+using namespace std;
+
+#define INCLUDE_SHORT_VECTOR
+
+FTKDataMatrixFromMCAlgo::FTKDataMatrixFromMCAlgo
+(const std::string& name, ISvcLocator* pSvcLocator) :
+   AthAlgorithm(name,pSvcLocator),
+   m_HWMODEID(2),
+   m_tower(-1),
+   m_invertIBLphiMatrix(1),
+   m_invertIBLphiData(1),
+   m_matrixVtxX(0),
+   m_matrixVtxY(0),
+   m_matrixVtxZ(0),
+   m_rmap(0),
+   m_MCmodulePositionCalculator(0),
+   m_DATAmodulePositionCalculator(0),
+   m_MCmatrixFile(0),
+   m_DATAmatrixFile(0),
+   m_debugFile(0)
+{
+   SetLogger(this);
+   declareProperty("MCmatrixFileName",m_MCmatrixFileName);
+   declareProperty("DATAmatrixFileName",m_DATAmatrixFileName);
+   declareProperty("debugFileName",m_debugFileName);
+   declareProperty("MCmodulePositionFileName",m_MCmodulePositionFileName);
+   declareProperty("DATAmodulePositionFileName",m_DATAmodulePositionFileName);
+   declareProperty("pmap_path", m_pmap_path);
+   declareProperty("rmap_path",m_rmap_path);
+   declareProperty("hwmodeid", m_HWMODEID);
+   declareProperty("tower", m_tower);
+   /* declareProperty("IBLMode",m_IBLMode);
+   declareProperty("FixEndcapL0",m_fixEndcapL0);
+   declareProperty("ITkMode",m_ITkMode); */
+   declareProperty("ModuleLUTPath", m_modulelut_path);
+   declareProperty("matrixVtxX",m_matrixVtxX);
+   declareProperty("matrixVtxY",m_matrixVtxY);
+   declareProperty("matrixVtxZ",m_matrixVtxZ);
+   declareProperty("dataVtxX",m_dataVtxX);
+   declareProperty("dataVtxY",m_dataVtxY);
+   declareProperty("dataVtxZ",m_dataVtxZ);
+   declareProperty("invertIBLphiMatrix",m_invertIBLphiMatrix);
+   declareProperty("invertIBLphiData",m_invertIBLphiData);
+}
+
+FTKDataMatrixFromMCAlgo::~FTKDataMatrixFromMCAlgo() {
+   if(m_DATAmatrixFile) delete m_DATAmatrixFile;
+   if(m_MCmatrixFile) delete m_MCmatrixFile;
+   if(m_debugFile) delete m_debugFile;
+   if(m_MCmodulePositionCalculator) delete m_MCmodulePositionCalculator;
+   if(m_DATAmodulePositionCalculator) delete m_DATAmodulePositionCalculator;
+   if(m_rmap) delete m_rmap;
+}
+
+void FTKDataMatrixFromMCAlgo::PostMessage(void) {
+   if     (FTKLogger::m_type==0)  ATH_MSG_FATAL(m_buffer->str());
+   else if(FTKLogger::m_type==1)  ATH_MSG_ERROR(m_buffer->str());
+   else if(FTKLogger::m_type==2)  ATH_MSG_WARNING(m_buffer->str());
+   else if(FTKLogger::m_type==3)  ATH_MSG_INFO(m_buffer->str());
+   else if(FTKLogger::m_type==4)  ATH_MSG_DEBUG(m_buffer->str());
+}
+
+StatusCode FTKDataMatrixFromMCAlgo::initialize() {
+   // open root files
+   int error=0;
+   FTKSetup &ftkset = FTKSetup::getFTKSetup();
+   ftkset.setHWModeSS(m_HWMODEID);
+   /*ftkset.setIBLMode(m_IBLMode);
+   ftkset.setfixEndcapL0(m_fixEndcapL0);
+   ftkset.setITkMode(m_ITkMode); */
+   if(m_pmap_path.empty()) {
+      ATH_MSG_FATAL("no plane map specified");
+   }
+   if(m_rmap_path.empty()) {
+      ATH_MSG_FATAL("no region map specified");
+   }
+
+   ATH_MSG_INFO("Loading plane map: "+m_pmap_path);
+   FTKPlaneMap* pmap = new FTKPlaneMap(m_pmap_path.c_str());
+   if (!(*pmap)) {
+      ATH_MSG_FATAL("Error using plane map: "+ m_pmap_path);
+   }
+   
+   ATH_MSG_INFO("Loading region map: "+m_rmap_path);
+   m_rmap = new FTKRegionMap(pmap, m_rmap_path.c_str());
+
+   if(m_HWMODEID==2) {
+      if(m_modulelut_path.empty()) {
+         ATH_MSG_FATAL("A module LUT is required with HWMODEID==2");
+	 return StatusCode::FAILURE;
+      } else {
+         m_rmap->loadModuleIDLUT(m_modulelut_path.c_str());
+      }
+   }
+
+   m_MCmatrixFile=new TFile(m_MCmatrixFileName.c_str());
+   m_DATAmatrixFile=new TFile(m_DATAmatrixFileName.c_str(),"recreate");
+   m_MCmodulePositionCalculator=
+      new FTKGhostHitCalculator(m_rmap,"FTKGhostHitCalculator_MC");
+   m_DATAmodulePositionCalculator=
+      new FTKGhostHitCalculator(m_rmap,"FTKGhostHitCalculator_data");
+   if(!m_MCmatrixFile->IsOpen()) {
+      ATH_MSG_FATAL("Can not open input matrix file \""+
+                    m_MCmatrixFileName+"\" for reading");
+      error++;
+   } else {
+      ATH_MSG_INFO("opening input matrix file \""+m_MCmatrixFileName+"\"");
+   }
+   if(!m_DATAmatrixFile->IsOpen()) {
+      ATH_MSG_FATAL("Can not open DATA matrix file \""+
+                    m_DATAmatrixFileName+"\" for writing");
+      error++;
+   } else {
+      ATH_MSG_INFO("opening output matrix file \""+m_DATAmatrixFileName+"\"");
+   }
+   if(!m_MCmodulePositionCalculator->loadModuleGeometry
+      (m_MCmodulePositionFileName,true,m_invertIBLphiMatrix)) {
+      ATH_MSG_FATAL("Can not load MC module position file \""+
+                    m_MCmodulePositionFileName+"\" for reading");
+      error++;
+   }
+   if(!m_DATAmodulePositionCalculator->loadModuleGeometry
+      (m_DATAmodulePositionFileName,true,m_invertIBLphiData)) {
+      ATH_MSG_FATAL("Can not open DATA module position file \""+
+                    m_DATAmodulePositionFileName+"\" for reading");
+      error++;
+   }
+   if(!m_debugFileName.empty()) {
+      m_debugFile=new TFile(m_debugFileName.c_str(),"recreate");
+      if(m_debugFile->IsOpen()) {
+         ATH_MSG_INFO("Debugging information is stored in "+
+                      m_debugFileName);
+      } else {
+         ATH_MSG_WARNING("File \""+m_debugFileName+
+                         "\"for storing debug information can not be opened");
+         delete m_debugFile;
+         m_debugFile=0;
+      }
+   }
+   if(error) {
+      return StatusCode::FAILURE;
+   } else {
+      return StatusCode::SUCCESS;
+   }
+}
+
+StatusCode FTKDataMatrixFromMCAlgo::execute() {
+   if(!m_DATAmatrixFile) return StatusCode::FAILURE;
+   // TTRee with debugging information
+   TVector3 matrixVtx(m_matrixVtxX,m_matrixVtxY,m_matrixVtxZ);
+   TVector3 dataVtx(m_dataVtxX,m_dataVtxY,m_dataVtxZ);
+   ATH_MSG_INFO("matrix file assumed to be relative to "+
+                TString::Format("(%lf,%lf,%lf)",
+                                matrixVtx(0),matrixVtx(1),matrixVtx(2)));
+   ATH_MSG_INFO("output matrix file will be relative to "+
+                TString::Format("(%lf,%lf,%lf)",
+                                dataVtx(0),dataVtx(1),dataVtx(2)));
+#ifdef WRITE_DEBUG_TREE
+   TTree *debugPix=0,*debugSCT=0;
+   int debug_tower,debug_hash,debug_plane;
+   float debug_track[5],debug_hit[2],debug_ghost[2],debug_data[2];
+#endif
+   vector<TH2 *> debug_coordHM(16),debug_coordMD(16),debug_resCurv(16);
+   if(m_debugFile) {
+      m_debugFile->cd();
+#ifdef WRITE_DEBUG_TREE
+      debugPix=new TTree("debugPix","debugPix");
+      debugSCT=new TTree("debugSCT","debugSCT");
+      debugPix->Branch("tower",&debug_tower,"tower/I");
+      debugPix->Branch("plane",&debug_plane,"plane/I");
+      debugPix->Branch("hash",&debug_hash,"hash/I");
+      debugPix->Branch("track",debug_track,"track[5]/F");
+      debugPix->Branch("hit",debug_hit,"hit[2]/F");
+      debugPix->Branch("ghost",debug_ghost,"ghost[2]/F");
+      debugPix->Branch("data",debug_data,"data[2]/F");
+      debugSCT->Branch("tower",&debug_tower,"tower/I");
+      debugSCT->Branch("plane",&debug_plane,"plane/I");
+      debugSCT->Branch("hash",&debug_hash,"hash/I");
+      debugSCT->Branch("track",debug_track,"track[5]/F");
+      debugSCT->Branch("hit",debug_hit,"hit/F");
+      debugSCT->Branch("ghost",debug_ghost,"ghost/F");
+      debugSCT->Branch("data",debug_data,"data/F");
+#endif
+      for(size_t i=0;i<debug_coordHM.size();i++) {
+         double w=800;
+         if(i<8) {
+            if(i&1) w=160;
+            else w=360.;
+         }
+         double x0=-0.1*w;
+         double x1=1.1*w;
+         debug_coordHM[i]=new TH2F(TString::Format("coordHM%d",(int)i),
+                                   ";hit;matrix",50,x0,x1,50,x0,x1);
+         debug_coordMD[i]=new TH2F(TString::Format("coordMD%d",(int)i),
+                                   ";matrix;output",50,x0,x1,50,x0,x1);
+         debug_resCurv[i]=new TH2F(TString::Format("resCurv%d",(int)i),
+                                   ";matrix;output",50,-0.001,0.001,50,-0.3*w,0.3*w);
+      }
+   }
+
+   // output directory
+   m_DATAmatrixFile->cd();
+   // copy tree "slice"
+   TTree *slice_tree;
+   m_MCmatrixFile->GetObject("slice",slice_tree);
+   if(slice_tree) {
+        double tmp_cmax;
+        double tmp_cmin;
+        int tmp_cslices;
+  
+        double tmp_phimax;
+        double tmp_phimin;
+        int tmp_phislices;
+  
+        double tmp_d0max;
+        double tmp_d0min;
+        int tmp_d0slices;
+  
+        double tmp_z0max;
+        double tmp_z0min;
+        int tmp_z0slices;
+  
+        double tmp_etamax;
+        double tmp_etamin;
+        int tmp_etaslices;
+
+        slice_tree->SetBranchAddress("c_max",&tmp_cmax);
+        slice_tree->SetBranchAddress("c_min", &tmp_cmin);
+        slice_tree->SetBranchAddress("c_slices", &tmp_cslices);
+        slice_tree->SetBranchAddress("phi_max", &tmp_phimax);
+        slice_tree->SetBranchAddress("phi_min", &tmp_phimin);
+        slice_tree->SetBranchAddress("phi_slices", &tmp_phislices);
+        slice_tree->SetBranchAddress("d0_max", &tmp_d0max);
+        slice_tree->SetBranchAddress("d0_min", &tmp_d0min);
+        slice_tree->SetBranchAddress("d0_slices", &tmp_d0slices);
+        slice_tree->SetBranchAddress("z0_max", &tmp_z0max);
+        slice_tree->SetBranchAddress("z0_min", &tmp_z0min);
+        slice_tree->SetBranchAddress("z0_slices", &tmp_z0slices);
+        slice_tree->SetBranchAddress("eta_max", &tmp_etamax);
+        slice_tree->SetBranchAddress("eta_min", &tmp_etamin);
+        slice_tree->SetBranchAddress("eta_slices", &tmp_etaslices);
+        slice_tree->GetEntry(0); 
+        delete slice_tree;
+        slice_tree=0;
+
+        m_DATAmatrixFile->cd();
+        slice_tree=new TTree("slice","slice");
+        slice_tree->Branch("c_max",&tmp_cmax);
+        slice_tree->Branch("c_min", &tmp_cmin);
+        slice_tree->Branch("c_slices", &tmp_cslices);
+        slice_tree->Branch("phi_max", &tmp_phimax);
+        slice_tree->Branch("phi_min", &tmp_phimin);
+        slice_tree->Branch("phi_slices", &tmp_phislices);
+        slice_tree->Branch("d0_max", &tmp_d0max);
+        slice_tree->Branch("d0_min", &tmp_d0min);
+        slice_tree->Branch("d0_slices", &tmp_d0slices);
+        slice_tree->Branch("z0_max", &tmp_z0max);
+        slice_tree->Branch("z0_min", &tmp_z0min);
+        slice_tree->Branch("z0_slices", &tmp_z0slices);
+        slice_tree->Branch("eta_max", &tmp_etamax);
+        slice_tree->Branch("eta_min", &tmp_etamin);
+        slice_tree->Branch("eta_slices", &tmp_etaslices);
+        slice_tree->Fill();
+        slice_tree->Write(0,TObject::kOverwrite);
+
+   } else {
+      ATH_MSG_ERROR("no slice tree found in \""+m_MCmatrixFileName+"\"");
+   }
+   // copy tree "montree"
+   /*TTree *montree;
+   m_MCmatrixFile->GetObject("montree",montree);
+   if(montree) {
+      montree->Write();
+   } else {
+      ATH_MSG_WARNING("no montree tree found in \""+m_MCmatrixFileName+"\"");
+      } */
+   gErrorAbortLevel=kError;
+   // loop over all am trees
+   for(int tower=0;tower<64;tower++) {
+      if((m_tower>=0)&&(tower!=m_tower)) continue;
+      TTree *mcTree;
+      TString amName=TString::Format("am%d",tower); 
+      m_MCmatrixFile->GetObject(amName,mcTree);
+#ifdef WRITE_DEBUG_TREE
+      debug_tower=tower;
+#endif
+      if(!mcTree) {
+         ATH_MSG_ERROR("no tree \""+amName+"\" found in \""+
+                       m_MCmatrixFileName+"\"");
+      } else {
+         ATH_MSG_INFO(TString::Format("Processing tower %d",tower) );
+         vector<int> errorCountPlane(m_rmap->getPlaneMap()->getNPlanes());
+         map<int,int> badModulePix,badModuleSCT;
+         int errorCountE=0;
+         int errorCountH=0;
+         // rename input tree
+         mcTree->SetName("tmptree");
+         int ndim,ndim2,nplanes;
+         mcTree->SetBranchAddress("ndim",&ndim);
+         mcTree->SetBranchAddress("ndim2",&ndim2);
+         mcTree->SetBranchAddress("nplanes",&nplanes);
+         mcTree->GetEntry(0);
+         ATH_MSG_INFO(TString::Format("ndim=%d ndim2=%d nplanes=%d",
+                                      ndim,ndim2,nplanes) );
+         double *Vec=new double[ndim];
+         mcTree->SetBranchAddress("Vec",Vec);
+         int *sectorID=new int[nplanes];
+         mcTree->SetBranchAddress("sectorID",sectorID);
+         int *hashID=new int[nplanes];
+         mcTree->SetBranchAddress("hashID",hashID);
+         float nhit;
+         mcTree->SetBranchAddress("nhit",&nhit);
+         double tmp_C_D_Phi_Coto_Z[5];
+         mcTree->SetBranchAddress("tmpC",tmp_C_D_Phi_Coto_Z+0);
+         mcTree->SetBranchAddress("tmpD",tmp_C_D_Phi_Coto_Z+1);
+         mcTree->SetBranchAddress("tmpPhi",tmp_C_D_Phi_Coto_Z+2);
+         mcTree->SetBranchAddress("tmpCoto",tmp_C_D_Phi_Coto_Z+3);
+         mcTree->SetBranchAddress("tmpZ",tmp_C_D_Phi_Coto_Z+4);
+         double *tmpx_C_D_Phi_Coto_Z=new double[5*ndim];
+         mcTree->SetBranchAddress("tmpxC",tmpx_C_D_Phi_Coto_Z+0*ndim);
+         mcTree->SetBranchAddress("tmpxD",tmpx_C_D_Phi_Coto_Z+1*ndim);
+         mcTree->SetBranchAddress("tmpxPhi",tmpx_C_D_Phi_Coto_Z+2*ndim);
+         mcTree->SetBranchAddress("tmpxCoto",tmpx_C_D_Phi_Coto_Z+3*ndim);
+         mcTree->SetBranchAddress("tmpxZ",tmpx_C_D_Phi_Coto_Z+4*ndim);
+         double *tmpcovx=new double[ndim2];
+         mcTree->SetBranchAddress("tmpcovx",tmpcovx);
+#ifdef INCLUDE_SHORT_VECTOR
+         std::vector<short>
+            *tmpintc=new std::vector<short>,
+            *tmpintphi=new std::vector<short>,
+            *tmpintd0=new std::vector<short>,
+            *tmpintz0=new std::vector<short>,
+            *tmpinteta=new std::vector<short>;
+         mcTree->SetBranchAddress("tmpintc",&tmpintc);
+         mcTree->SetBranchAddress("tmpintphi",&tmpintphi);
+         mcTree->SetBranchAddress("tmpintd0",&tmpintd0);
+         mcTree->SetBranchAddress("tmpintz0",&tmpintz0);
+         mcTree->SetBranchAddress("tmpinteta",&tmpinteta);
+#endif
+         // create output tree
+         m_DATAmatrixFile->cd();
+         TTree *dataTree=new TTree
+            (amName,TString::Format("Ambank %d para",tower));
+
+         dataTree->Branch("ndim",&ndim,"ndim/I");
+         dataTree->Branch("ndim2",&ndim2,"ndim2/I");
+         dataTree->Branch("nplanes",&nplanes,"nplanes/I");
+         dataTree->Branch("Vec", Vec,"Vec[ndim]/D");
+         dataTree->Branch("sectorID",sectorID,"sectorID[nplanes]/I");
+         dataTree->Branch("hashID",hashID,"hashID[nplanes]/I");
+         dataTree->Branch("nhit", &nhit,"nhit/F");\
+         dataTree->Branch("tmpC",tmp_C_D_Phi_Coto_Z+0,"tmpC/D");
+         dataTree->Branch("tmpD",tmp_C_D_Phi_Coto_Z+1,"tmpD/D");
+         dataTree->Branch("tmpPhi",tmp_C_D_Phi_Coto_Z+2,"tmpPhi/D");
+         dataTree->Branch("tmpCoto",tmp_C_D_Phi_Coto_Z+3,"tmpCoto/D");
+         dataTree->Branch("tmpZ",tmp_C_D_Phi_Coto_Z+4,"tmpZ/D");
+         dataTree->Branch("tmpxC",tmpx_C_D_Phi_Coto_Z+0*ndim,"tmpxC[ndim]/D");
+         dataTree->Branch("tmpxD",tmpx_C_D_Phi_Coto_Z+1*ndim,"tmpxD[ndim]/D");
+         dataTree->Branch("tmpxPhi",tmpx_C_D_Phi_Coto_Z+2*ndim,"tmpxPhi[ndim]/D");
+         dataTree->Branch("tmpxCoto",tmpx_C_D_Phi_Coto_Z+3*ndim,"tmpxCoto[ndim]/D");
+         dataTree->Branch("tmpxZ",tmpx_C_D_Phi_Coto_Z+4*ndim,"tmpxZ[ndim]/D");
+         dataTree->Branch("tmpcovx",tmpcovx,"tmpcovx[ndim2]/D");
+         // drop these for tests
+#ifdef INCLUDE_SHORT_VECTOR
+         dataTree->Branch("tmpintc", &tmpintc);
+         dataTree->Branch("tmpintphi", &tmpintphi);
+         dataTree->Branch("tmpintd0", &tmpintd0);
+         dataTree->Branch("tmpintz0", &tmpintz0);
+         dataTree->Branch("tmpinteta", &tmpinteta);
+#endif
+         // loop over all entries (c.f. sectors)
+         for(int iEnt=0;iEnt<mcTree->GetEntries(); iEnt++) {
+            mcTree->GetEntry(iEnt);
+            if(nhit<ndim) {
+               errorCountH++;
+               continue;
+            }
+            // transform here the coordinates to the new module geometry
+            TVectorD avgT(5);
+            TVectorD avgX(ndim);
+            TMatrixD avgTX(5,ndim);
+            TMatrixDSym avgXX(ndim);
+            // <t>
+            for(int i=0;i<5;i++) {
+               avgT(i)=tmp_C_D_Phi_Coto_Z[i]/nhit;
+            }
+            // <x>
+            for(int i=0;i<ndim;i++) {
+               avgX(i)=Vec[i]/nhit;
+            }
+            // <tx>
+            for(int i=0;i<5;i++) {
+               for(int j=0;j<ndim;j++) {
+                  avgTX(i,j)=tmpx_C_D_Phi_Coto_Z[j+ndim*i]/nhit-avgX(j)*avgT(i);
+               }
+            }
+            // <xx>-<x>*<x>
+            for(int j=0;j<ndim;j++) {
+               for(int i=0;i<=j;i++) {
+                  avgXX(i,j)=tmpcovx[i*ndim+j]/nhit-avgX(i)*avgX(j);
+                  avgXX(j,i)=avgXX(i,j);
+               }
+            }
+            TMatrixDSymEigen EXX(avgXX);
+            TVectorD eval=EXX.GetEigenValues();
+            TMatrixD evec=EXX.GetEigenVectors();
+            TMatrixDSym H(ndim);
+            int error=0;
+            for(int i=0;i<ndim;i++) {
+               for(int j=0;j<ndim;j++) {
+                  for(int k=0;k<ndim;k++) {
+                     if(eval(k)<=0.0) {
+                        error++;
+                        break;
+                     }
+                     H(i,j) += evec(i,k)*evec(j,k)/eval(k);
+                  }
+                  if(error) break;
+               }
+               if(error) break;
+            }
+            // if there is an error, skip further corrections
+            if(error) {
+               errorCountH++;
+               /* cout<<"nhit="<<nhit<<"\n";
+               cout<<"avgT\n";
+               avgT.Print();
+               cout<<"avgX\n";
+               avgX.Print();
+               cout<<"avgTX\n";
+               avgTX.Print();
+               cout<<"avgXX\n";
+               avgXX.Print();
+               exit(0); */
+            } else {
+               // matrix A:  t = A*(x-t0) + t0
+               //   TMatrixD A(avgTX,TMatrixD::kMult,H);
+               //
+               // <tt>-<t>*<t>
+               TMatrixDSym avgTT(H.Similarity(avgTX));
+               // eigenvalue decomposition
+               TMatrixDSymEigen ETT(avgTT);
+               TMatrixD T=ETT.GetEigenVectors();
+               TMatrixD Tinv(T);
+               TVectorD evT=ETT.GetEigenValues();
+               for(int i=0;i<5;i++) {
+                  for(int j=0;j<5;j++) {
+                     double sqrtEV=sqrt(evT(j));
+                     T(i,j) *= sqrtEV;
+                     Tinv(i,j) /= sqrtEV;
+                  }
+               }
+               TMatrixD BTinv(avgTX,TMatrixD::kTransposeMult,Tinv);
+               //
+               // calculate alignment differences for DATA-MC
+               // for central track positions and shifted 
+               // by +/- eigenvectors
+               TVectorD d_mcX(ndim);
+               TMatrixD d_mcXT(ndim,5);
+               TMatrixD d_mcXX(ndim,ndim);
+               int planeError=0;
+               for(int n=0;n<11;n++) {
+                  // n=0:   <t>
+                  // n=1,2  <t> +/- <T0>
+                  // n=3,4  <t> +/- <T1>
+                  //    ...
+                  // n=9,10  <t> +/- <T4>
+                  TVectorD track(avgT);
+                  double sign= (n&1) ? 1. : -1.;
+                  int iEV=(n-1)/2;
+                  if(n) {
+                     for(int j=0;j<5;j++) {
+                        track(j) +=sign*T(j,iEV);
+                     }
+                  }
+                  //cout<<"track\n";
+                  //track.Print();
+                  static double const B_FACTOR=-0.3*2.083;
+                  double Q_over_pt=2.0*track(0);
+                  double rho=B_FACTOR* Q_over_pt;
+                  double d0=track(1);
+                  double phi=track(2);
+                  double cotTh=track(3);
+                  double z0=track(4);
+                  double sinPhi0=sin(phi);
+                  double cosPhi0=cos(phi);
+                  int icoord=0;
+                  TVectorD d_mc(ndim);
+                  for(int plane=0;plane<nplanes;plane++) {
+                     int hash=hashID[plane];
+                     double xData[2],xMC[2];
+                     int errorMC=m_MCmodulePositionCalculator->
+                        extrapolateTo(plane,hash,rho,cotTh,z0,d0,
+                                      sinPhi0,cosPhi0,&matrixVtx,xMC);
+                     int errorData=m_DATAmodulePositionCalculator->
+                        extrapolateTo(plane,hash,rho,cotTh,z0,d0,
+                                       sinPhi0,cosPhi0,&dataVtx,xData);
+                     int ncoord=m_rmap->getPlaneMap()->isSCT(plane) ? 1 : 2;
+                     if(errorMC||errorData) {
+                        if(ncoord==2) {
+                           badModulePix[hash]|=(1<<(errorMC+8))|(1<<errorData);
+                        } else {
+                           badModuleSCT[hash]|=(1<<(errorMC+8))|(1<<errorData);
+                        }
+                        planeError |= (1<<plane);
+                        error++;
+                     } else {
+                        for(int j=0;j<ncoord;j++) {
+                           d_mc(icoord+j) = xData[j]-xMC[j];
+                        }
+#ifdef WRITE_DEBUG_TREE
+                        if((n==0) && (m_debugFile)) {
+                           debug_hash=hash;
+                           debug_plane=plane;
+                           for(int j=0;j<ncoord;j++) {
+                              debug_hit[j]=avgX(icoord+j);
+                              debug_ghost[j]=xMC[j];
+                              debug_data[j]=xData[j];
+                           }
+                           for(int i=0;i<5;i++) {
+                              debug_track[i]=track(i);
+                           }
+                           /*FTK_ModuleGeometry const *module=
+                              m_MCmodulePositionCalculator->
+                              findModule(plane,hash); */
+                           if(ncoord==2) {
+                              debugPix->Fill();
+                           } else {
+                              debugSCT->Fill();
+                           }
+                        }
+#endif
+                        if(m_debugFile) {
+                           // fill monitoring histograms
+                           for(int j=0;j<ncoord;j++) {
+                              if(debug_coordHM[icoord+j])
+                                 debug_coordHM[icoord+j]->Fill
+                                    (avgX(icoord+j),xMC[j]);
+                              if(debug_coordMD[icoord+j])
+                                 debug_coordMD[icoord+j]->Fill
+                                    (xMC[j],xData[j]);
+                              if(debug_resCurv[icoord+j])
+                                 debug_resCurv[icoord+j]->Fill
+                                    (xMC[j]-avgX(icoord+j),track(0));
+                           }
+                        }
+                     }
+                     icoord += ncoord;
+                  }
+                  if(n==0) {
+                     // average difference data-mc
+                     d_mcX=d_mc;
+                  } else {
+                     TVectorD deltaX(d_mc-d_mcX);
+                     for(int i=0;i<ndim;i++) {
+                        for(int k=0;k<5;k++) {
+                           // sum of deltaX*deltaT
+                           d_mcXT(i,k) += 0.5*deltaX(i)*sign*T(k,iEV);
+                        }
+                        for(int j=0;j<ndim;j++) {
+                           // sums of deltaX*deltaX and correlations
+                           // involving B=avgTX
+                           d_mcXX(i,j) += 0.5*
+                              (deltaX(i)*sign*BTinv(j,iEV)+
+                               deltaX(j)*sign*BTinv(i,iEV)+
+                               deltaX(i)*deltaX(j));
+                        }
+                     }
+                  }
+               }
+               if(!error) {
+                  // apply alignment changes to the coordinate sums
+
+                  // coordinate shifts (vector d)
+                  float nhit0=nhit;
+                  //nhit=0;
+                  for(int i=0;i<ndim;i++) {
+                     Vec[i]+= d_mcX(i)*nhit;
+                  }
+                  // rotations (matrices M and E)
+                  for(int i=0;i<5;i++) {
+                     for(int j=0;j<ndim;j++) {
+                        tmpx_C_D_Phi_Coto_Z[j+ndim*i]+=nhit*
+                           (d_mcX(j)*avgT(i)+d_mcXT(j,i));
+                     }
+                  }
+                  for(int j=0;j<ndim;j++) {
+                     for(int i=0;i<=j;i++) {
+                        tmpcovx[i*ndim+j]+= nhit*
+                           (avgX(i)*d_mcX(j)+avgX(j)*d_mcX(i)+
+                            d_mcX(i)*d_mcX(j)+d_mcXX(i,j));
+                        tmpcovx[j*ndim+i]=tmpcovx[i*ndim+j];
+                     }
+                  }
+                  nhit=nhit0;
+               } else {
+                  for(size_t k=0;k<errorCountPlane.size();k++) {
+                     if(planeError & (1<<k)) errorCountPlane[k]++;
+                     //cout<<"plane "<<k<<" error\n";
+                  }
+                  errorCountE++;
+                  //exit(0);
+               }
+            }
+
+            if((errorCountH |errorCountE)==0) {
+               dataTree->Fill();
+            }
+
+            /*if(//(iEnt<10)||
+               //((iEnt<100)&&(iEnt%10 ==0))||
+               //((iEnt<1000)&&(iEnt%100 ==0))||
+               ((iEnt<10000)&&(iEnt%1000 ==0))||
+               ((iEnt%10000 ==0))) {
+               ATH_MSG_INFO(TString::Format
+                            ("sector %d nErrorE=%d nErrorH=%d",
+                             iEnt,errorCountE,errorCountH));
+                             } */
+         }
+
+         // save to output file
+         m_DATAmatrixFile->cd();
+         dataTree->Write(0,TObject::kOverwrite);
+
+         if(errorCountE|errorCountH) {
+            TString errorMsg=TString::Format
+               ("tower=%d errors (%d+%d)/%lld sectors with error",
+                tower,errorCountE,errorCountH,
+                mcTree->GetEntries());
+            if(errorCountE) {
+               errorMsg+=" by plane:";
+               for(size_t k=0;k<errorCountPlane.size();k++) {
+                  errorMsg += TString::Format(" %d",errorCountPlane[k]);
+               }
+            }
+            ATH_MSG_WARNING(errorMsg);
+            if(badModulePix.size()) {
+               TString pixErrors("pixel module errors");
+               for(auto m=badModulePix.begin();m!=badModulePix.end();m++) {
+                  pixErrors+=TString::Format(" %d:%x",(*m).first,(*m).second);
+               }
+               ATH_MSG_WARNING(pixErrors);
+            }
+            if(badModuleSCT.size()) {
+               TString sctErrors("SCT module errors");
+               for(auto m=badModuleSCT.begin();m!=badModuleSCT.end();m++) {
+                  sctErrors+=TString::Format(" %d:%x",(*m).first,(*m).second);
+               }
+               ATH_MSG_WARNING(sctErrors);
+            }
+         }
+
+         delete [] tmpcovx;
+         delete [] tmpx_C_D_Phi_Coto_Z;
+         delete [] hashID;
+         delete [] sectorID;
+         delete [] Vec;
+      }
+   }
+   if(m_DATAmatrixFile) delete m_DATAmatrixFile;
+   m_DATAmatrixFile=0;
+#ifdef WRITE_DEBUG_TREE
+   if(debugPix) {
+      m_debugFile->cd();
+      debugPix->Write(0,TObject::kOverwrite);
+   }
+   if(debugSCT) {
+      m_debugFile->cd();
+      debugSCT->Write(0,TObject::kOverwrite);
+   }
+#endif
+   for(size_t i=0;i<debug_coordHM.size();i++) {
+      if(m_debugFile) m_debugFile->cd();
+      if(debug_coordHM[i]) debug_coordHM[i]->Write(0,TObject::kOverwrite);
+      if(debug_coordMD[i]) debug_coordMD[i]->Write(0,TObject::kOverwrite);
+      if(debug_resCurv[i]) debug_resCurv[i]->Write(0,TObject::kOverwrite);
+   }
+   if(m_debugFile) delete m_debugFile;
+   m_debugFile=0;
+   return StatusCode::SUCCESS;
+}
+
+StatusCode FTKDataMatrixFromMCAlgo::finalize() {
+   return StatusCode::SUCCESS;
+}
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKGhostHitCalculator.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKGhostHitCalculator.cxx
new file mode 100644
index 000000000000..c4039c692efd
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKGhostHitCalculator.cxx
@@ -0,0 +1,647 @@
+#include "TrigFTKBankGen/FTKGhostHitCalculator.h"
+#include "TrigFTKSim/FTKRootFile.h"
+#include "TrigFTKSim/FTKRegionMap.h"
+#include "TrigFTKSim/ftk_dcap.h"
+#include "TrigFTKSim/FTKTruthTrack.h"
+#include "TrigFTKSim/FTKSetup.h"
+#include <TTree.h>
+
+
+bool FTK_ModuleGeometry::extrapolate
+(double rho,double cotTh,double z0,double d0,double sinPhi0,double cosPhi0,
+ TVector3 const *trackVertex,double *xLocPtr,TVector2 *xPtr,double *sPtr) 
+   const {
+   // rough track extrapolation in phi
+   TVector3 d(-d0*sinPhi0,d0*cosPhi0,z0);
+   if(trackVertex) d += *trackVertex;
+   TVector3 cd(m_center-d);
+   double r=TMath::Hypot(cd.X(),cd.Y());
+   double product=(cd.X()*cosPhi0+cd.Y()*sinPhi0)/r;
+   // skip modules if track is not within +/-25 degree in phi
+   if(product<0.5) {
+      /*std::cout<<"id="<<m_id<<"/"<<m_plane<<" rho="<<rho<<" cotTh="<<cotTh<<" z0="<<z0<<" d0="<<d0
+          <<" sinPhi="<<sinPhi0<<" cosPhi="<<cosPhi0
+          <<" center="<<m_center.X()<<","<<m_center.Y()<<","<<m_center.Z()
+          <<"\n";
+          //exit(0); */
+      return false;
+   }
+   TVector2 x;
+   TVector3 const &dir0(m_phiAxis);
+   TVector3 const &dir1(m_etaAxis);
+   // iterate to get accurate extrapolation to module plane
+   double s;
+   bool haveS=false;
+   for(int iter=0;iter<3;iter++) {
+      // 1/rho may be large (or infinite)
+      // but sin(s*rho)/rho  and  (1-cos(s*rho))/rho are finite
+      // further complication:
+      // 1-cos(s*rho) may be small -> calculation using cos() is inaccurate
+      //  -> calculate using sin(s*rho/2)
+      double sRho;
+      if(haveS) {
+         sRho=s*rho;
+      } else {
+         double rRho=r*rho;
+         if(fabs(rRho)>1.E-10) {
+            sRho=2.*asin(0.5*rRho);
+            s=sRho/rho;
+         } else {
+            // 2*arcsin(x/2) ~= x*(1+x^2/24) 
+            double corr=(1.+rRho*rRho/24.);
+            s=r*corr;
+            sRho=rRho*corr;
+         }
+      }
+      double sinSrho_byRho;
+      double one_minus_cosSrho_byRho;
+      if(fabs(sRho)>1.E-10) {
+         sinSrho_byRho=sin(sRho)/rho;
+         double h=sin(0.5*sRho); 
+         // h*h = sin^2(0.5*sRho)
+         //     = 1/2* (sin^2(0.5*sRho)+1-cos^2(0.5*sRho))
+         //     = 1/2* (1 - cos(sRho))
+         one_minus_cosSrho_byRho = 2.*h*h/rho; //(1-cos(sRho))/rho;
+      } else {
+         // sin(x) ~= x*(1-x^2/6)
+         sinSrho_byRho=s-sRho*sRho*s/6.;
+         // 1-cos(x) ~= x^2*(1-x^2/24)
+         one_minus_cosSrho_byRho=s*sRho*(0.5-sRho*sRho/24.);
+      }
+      // h is the difference vector
+      // of the extrapolated helix and the module centre
+      TVector3 h(cosPhi0*sinSrho_byRho-sinPhi0*one_minus_cosSrho_byRho,
+                 sinPhi0*sinSrho_byRho+cosPhi0*one_minus_cosSrho_byRho,
+                 s*cotTh);
+      h-=cd;
+      // projection on strip phi axis
+      // projection on strip eta axis
+      x=TVector2(dir0.Dot(h),dir1.Dot(h));
+      // updated estimate of impact point on module plane minus
+      TVector3 impact=cd+dir0*x.X()+dir1*x.Y();
+      if(fabs(dir1.Z())>0.5) {
+         // barrel module
+         r=TMath::Hypot(impact.X(),impact.Y());
+         haveS=false;
+      } else {
+         // endcap module
+         s=impact.Z()/cotTh;
+         haveS=true;
+      }
+   }
+   if(xLocPtr) {
+      xLocPtr[0]=(x.X()+m_width.X()*0.5)/m_pitch.X();
+      xLocPtr[1]=(x.Y()+m_width.Y()*0.5)/m_pitch.Y();
+   }
+   if(xPtr) {
+      *xPtr = x;
+   }
+   if(sPtr) {
+      *sPtr =s;
+   }
+   return true;
+}
+
+FTKGhostHitCalculator::FTKGhostHitCalculator
+(const FTKRegionMap *rmap,std::string const &name)
+   : FTKLogging(name),m_rmap(rmap) {
+   // extract module to plane mapping
+   //  m_idByPlane gives for each plane the set of modules 
+   m_planeFromPIXid.clear();
+   m_plane_From_SCTid.clear();
+   for(int tower=0;tower<m_rmap->getNumRegions();tower++) {
+      for(int plane=0;plane<m_rmap->getNPlanes();plane++) {
+         std::map<int,int> &planeByID=m_rmap->getPlaneMap()->isPixel(plane) ?
+            m_planeFromPIXid : m_plane_From_SCTid;
+         std::map<unsigned int,unsigned int> tpMap=
+            m_rmap->getGlobalToLocalMapping(tower,plane);
+         for(std::map<unsigned int,unsigned int>::const_iterator
+                iID=tpMap.begin();iID!=tpMap.end();iID++) {
+            planeByID[(*iID).first]=plane;
+         }
+      }
+   }
+}
+
+int FTKGhostHitCalculator::loadModuleGeometry
+(std::string const &name,bool markAllBad,bool invertIBLphi) {
+   TDirectory *file=FTKRootFile::Instance()->OpenRootFileReadonly(name.c_str());
+   if(file) {
+      Info("LoadModueGeoemetry")
+         <<"reading \""<<name<<"\""<<" markAllBad="<<markAllBad
+         <<" invertIBLphi="<<invertIBLphi<<"\n";
+      int r=loadModuleGeometry(file,markAllBad,invertIBLphi);
+      delete file;
+      if(!r) {
+         Error("loadModuleGeometry")
+            <<"failed to load module geometry from "<<name<<"\n";
+      }
+      return r;
+   } else {
+      Error("loadModuleGeometry")<<"failed to open "<<name<<" as root file\n";
+      return 0;
+   }
+}
+
+int FTKGhostHitCalculator::addBadModules(std::string const &name) {
+   ftk_dcap::istream moduleList;
+   const bool ok_read = ftk_dcap::open_for_read(name,moduleList);
+   if (!moduleList || !ok_read) {
+      Error("addBadModules")<<"failed to open file "<<name<<" for reading\n";
+      return 0;
+   } else {
+      int r=addBadModules(moduleList);
+      if(!r) {
+         Error("addBadModules")<<"failed to read bad modules from "<<name<<"\n";
+      }
+      return r;
+   }
+}
+
+int FTKGhostHitCalculator::addBadModules(std::istream &in) {
+   int r=1;
+   std::set<int> SCTmodules,PIXmodules;
+   std::string line;
+   int nline=0;
+   while(getline(in,line)) {
+      nline++;
+      std::istringstream lineRead(line);
+      int tmpisPixel,tmpBEC,tmpSector,tmpPlane,tmpEtaModule,tmpPhiModule,
+         tmpSection,tmpidhash;
+      lineRead >>tmpisPixel >>tmpBEC >>tmpSector >>tmpPlane >>tmpEtaModule
+               >>tmpPhiModule >>tmpSection>>tmpidhash;
+      if(lineRead.fail()) {
+         Error("addBadModules")
+            <<"problem to read bad modules, line="<<nline
+            <<" : "<<line<<"\n";
+         r=0;
+         continue;
+      }
+      std::set<int> &moduleSet=(tmpisPixel ? PIXmodules : SCTmodules);
+      if(!moduleSet.insert(tmpidhash).second) {
+         Warning("addBadModules")
+            <<"skipping duplicate module isPixel="<<tmpisPixel<<" id="
+            <<tmpidhash<<"\n";
+      }
+   }
+   int nPixRead=PIXmodules.size();
+   int nPix=addBadPixelModules(PIXmodules);
+   int nSCTRead=SCTmodules.size();
+   int nSCT=addBadSCTModules(SCTmodules);
+   if(nPixRead==nPix) {
+      Info("addBadModules")<<"Using "<<nPix<<" dead pixel modules\n";
+   } else {
+      Info("addBadModules")
+         <<"Using "<<nPix<<" dead pixel modules ("<<nPixRead<<" requested)\n";
+   }
+   if(nSCTRead==nSCT) {
+      Info("addBadModules")<<"Using "<<nSCT<<" dead SCT modules\n";
+   } else {
+      Info("addBadModules")
+         <<"Using "<<nSCT<<" dead SCT modules ("<<nSCTRead<<" requested)\n";
+   }
+   return r;
+}
+
+FTK_ModuleGeometry const *FTKGhostHitCalculator::findModule(size_t plane,int moduleID) const {
+   FTK_ModuleGeometry const *r=0;
+   if(plane<m_geometryData.size()) {
+      auto modulePtr=m_geometryData[plane].find(moduleID);
+      if(modulePtr!=m_geometryData[plane].end()) {
+         r= &(*modulePtr).second;
+      }
+   }
+   return r;
+}
+
+int FTKGhostHitCalculator::extrapolateTo
+(size_t plane,int moduleID,double rho,double cotTh,double z0,double d0,
+ double sinPhi0,double cosPhi0,TVector3 const *trackVertex,double *x) const {
+   int r=0;
+   if(plane<m_geometryData.size()) {
+      auto modulePtr=m_geometryData[plane].find(moduleID);
+      if(modulePtr!=m_geometryData[plane].end()) {
+         if(!(*modulePtr).second.extrapolate
+            (rho,cotTh,z0,d0,sinPhi0,cosPhi0,trackVertex,x,0,0)) {
+            r=3;
+         }
+      } else {
+         r=2;
+         //Warning("extrapolateTo")
+         //   <<"module "<<moduleID<<" not found in plane "<<plane<<"\n";
+      }
+   } else {
+      r=1;
+      Error("extrapolateTo")
+         <<"bad plane number "<<plane<<" max="<<m_geometryData.size()<<"\n";
+   }
+   return r;
+}
+
+int FTKGhostHitCalculator::loadModuleGeometry
+(TDirectory *source,bool markAllBad,bool invertIBLphi) {
+   // initialize empty list of modules
+   m_geometryData.resize(0);
+   m_geometryData.resize(m_rmap->getPlaneMap()->getNPlanes());
+
+   // read modules from TTree
+   TTree *tree;
+   source->GetObject("modulePositions",tree);
+   int r=1;
+   
+   std::set<int> SCTmodules,PIXmodules;
+   if(tree) {
+      Int_t idhash;
+      Int_t isbad,isPixel,hitSector,isBLayer;
+      Int_t swapPhi,swapEta;
+      Float_t center[3],phiAxis[3],etaAxis[3],width,length,phiPitch,etaPitch;
+      Float_t sinTilt;
+      tree->SetBranchAddress("id",&idhash);
+      tree->SetBranchAddress("isPixel",&isPixel);
+      tree->SetBranchAddress("isBLayer",&isBLayer);
+      tree->SetBranchAddress("hitSector",&hitSector);
+      tree->SetBranchAddress("width",&width);
+      tree->SetBranchAddress("length",&length);
+      tree->SetBranchAddress("phiPitch",&phiPitch);
+      tree->SetBranchAddress("etaPitch",&etaPitch);
+      tree->SetBranchAddress("phiAxis",phiAxis);
+      tree->SetBranchAddress("etaAxis",etaAxis);
+      tree->SetBranchAddress("center",center);
+      tree->SetBranchAddress("isbad",&isbad);
+      tree->SetBranchAddress("swapPhi",&swapPhi);
+      tree->SetBranchAddress("swapEta",&swapEta);
+      tree->SetBranchAddress("sinTilt",&sinTilt);
+      m_geometryData.resize(m_rmap->getNPlanes());
+      int nLoad[2],nFTK[2],nDuplicate[2];
+      std::vector<int> rejected(4);
+      for(int i=0;i<2;i++) {
+         nLoad[i]=0;
+         nFTK[i]=0;
+         nDuplicate[i]=0;
+      }
+      for(int i=0;i<tree->GetEntries();i++) {
+         tree->GetEntry(i);
+         nLoad[isPixel ? 1 : 0] ++;
+         int plane=-1;
+         std::map<int,int> const &id2plane=
+            (isPixel ? m_planeFromPIXid : m_plane_From_SCTid);
+         std::map<int,int>::const_iterator iID=id2plane.find(idhash);
+         if(iID != id2plane.end()) {
+            plane=(*iID).second;
+         } else {
+            plane=isPixel ? -2 : -1;
+         }
+         if((plane>=0)&&(plane<(int)m_geometryData.size())) {
+            nFTK[isPixel ? 1 : 0] ++;  
+            std::map<int,FTK_ModuleGeometry>::iterator iModule=
+               m_geometryData[plane].find(idhash);
+            if(iModule!=m_geometryData[plane].end()) {
+               nDuplicate[isPixel ? 1 : 0] ++;
+               Warning("loadModuleGeometry")
+                  <<"skipping duplicate module isPixel="
+                  <<isPixel<<" id="<<idhash<<"\n";
+            } else {
+               FTK_ModuleGeometry &m=m_geometryData[plane][idhash];
+               m.m_center.SetXYZ(center[0],center[1],center[2]);
+               m.m_phiAxis.SetXYZ(phiAxis[0],phiAxis[1],phiAxis[2]);
+               m.m_etaAxis.SetXYZ(etaAxis[0],etaAxis[1],etaAxis[2]);
+
+               // fix for IBL inverted phi axis
+               if(isBLayer && invertIBLphi) {
+                  m.m_phiAxis *= -1.0;
+               }
+               //m.m_phiAxis.SetMag(1.0);
+               //m.m_etaAxis.SetMag(1.0);
+               double test=m.m_phiAxis.Dot(m.m_etaAxis);
+               if(TMath::Abs(test)>1.E-5) {
+                  Error("loadModuleGeometry")
+                     <<"phi axis ["<<m.m_phiAxis.X()<<","<<m.m_phiAxis.Y()
+                     <<","<<m.m_phiAxis.Z()<<"] and eta axis ["
+                     <<m.m_etaAxis.X()<<","<<m.m_etaAxis.Y()
+                     <<","<<m.m_etaAxis.Z()<<"] not orthogonal "<<test<<"\n";
+               }
+               m.m_pitch.Set(phiPitch,etaPitch);
+               m.m_width.Set(width,length);
+               m.m_isPixel=isPixel;
+               m.m_id=idhash;
+               m.m_plane=plane;
+               m.m_hitSector=hitSector;
+               if(isbad || markAllBad) {
+                  if(isPixel) {
+                     PIXmodules.insert(idhash);
+                  } else {
+                     SCTmodules.insert(idhash);
+                  }
+               }
+            }
+         } else {
+            int iReject=isPixel ? 0 : 1;
+            if(center[2]>0.) iReject+=2;
+            rejected[iReject]++;
+         }
+      }
+      delete tree;
+      Info("loadModuleGeometry")
+         <<"Modules found: SCT "<<nFTK[0]<<"/"<<nLoad[0]
+         <<" rejected: "<<rejected[0]<<"/"<<rejected[1]
+         <<"/"<<rejected[2]<<"/"<<rejected[3]
+         <<" Pixel "<<nFTK[1]<<"/"<<nLoad[1]
+         <<" Duplicates: SCT="<<nDuplicate[0]<<" Pixel="<<nDuplicate[1]<<"\n";
+   } else {
+      Error("loadModuleGeometry")<<"unable to load TTree \"modulePositions\"\n";
+      r=0;
+   }
+   addBadPixelModules(PIXmodules);
+   addBadSCTModules(SCTmodules);
+   /* for(size_t plane=0;plane<m_geometryData.size();plane++) {
+      std::cout<<"=========== modulelocator for plane="<<plane<<"\n";
+      FTK_ModuleLocator &moduleLocator=m_moduleLocatorByPlane[plane];
+      moduleLocator.print();
+      } */
+   return r;
+}
+
+void  FTKGhostHitCalculator::clearBadModuleList(void) {
+   Info("clearBadModuleList")<<"reset bad modules, pixel "<<m_badPixel.size()
+                             <<" SCT "<<m_badSCT.size()<<"\n";
+   m_badPixel.clear();
+   m_badSCT.clear();
+   updateCalculator();
+}
+
+void FTKGhostHitCalculator::updateCalculator(void) {
+   //
+   m_moduleLocatorByPlane.resize(0);
+   m_moduleLocatorByPlane.resize(m_geometryData.size());
+   //
+   for(size_t plane=0;plane<m_geometryData.size();plane++) {
+      std::map<int,FTK_ModuleGeometry> const &planeData(m_geometryData[plane]);
+      FTK_ModuleLocator &moduleLocator=m_moduleLocatorByPlane[plane];
+      for(std::map<int,FTK_ModuleGeometry>::const_iterator im=planeData.begin();
+          im!=planeData.end();im++) {
+         int id=(*im).first;
+         FTK_ModuleGeometry const *module=&((*im).second);
+         std::set<int> const &badList=module->m_isPixel ? m_badPixel : m_badSCT;
+         if(badList.find(id)!=badList.end()) {
+            // insert this module into the module locator
+            moduleLocator.insert(module);
+         }
+      }
+   }
+}
+
+FTKHit *FTKGhostHitCalculator::addGhostHit
+(FTKTruthTrack const &track,int plane, FTK_ModuleGeometry *module) const {
+   return m_moduleLocatorByPlane[plane].locate(track,module);
+}
+
+bool FTKGhostHitCalculator::isBad(int plane,int moduleID) const {
+   std::map<int,FTK_ModuleGeometry> const &planeData=m_geometryData[plane];
+   std::map<int,FTK_ModuleGeometry>::const_iterator iID=
+      planeData.find(moduleID);
+   if(iID!=planeData.end()) {
+      std::set<int> const &badSet=
+         (*iID).second.m_isPixel ? m_badPixel : m_badSCT;
+      return badSet.find(moduleID)!=badSet.end();
+   }
+   return false;
+}
+
+int FTKGhostHitCalculator::addBadPixelModules(std::set<int> const &bad) {
+   int n0=m_badPixel.size();
+   m_badPixel.insert(bad.begin(),bad.end());
+   Info("addBadPixelModules")
+      <<"inserting "<<bad.size()<<" bad modules, nBad increases from "
+      <<n0<<" to "<< m_badPixel.size()<<"\n";
+   updateCalculator();
+   return 0;
+}
+
+int FTKGhostHitCalculator::addBadSCTModules(std::set<int> const &bad) {
+   int n0=m_badSCT.size();
+   m_badSCT.insert(bad.begin(),bad.end());
+   Info("addBadSCTModules")
+      <<"inserting "<<bad.size()<<" bad modules, nBad increases from "
+      <<n0<<" to "<< m_badSCT.size()<<"\n";
+   updateCalculator();
+   return 0;
+}
+
+void FTK_ModuleLocator::insert(FTK_ModuleGeometry const *module) {
+   std::vector<double> ri(2),zi(2);
+   for(int ix=0;ix<2;ix++) {
+      for(int iy=0;iy<2;iy++) {
+         TVector3 pos=module->m_center
+            +module->m_width.X()*(ix-0.5)*module->m_phiAxis
+            +module->m_width.Y()*(iy-0.5)*module->m_etaAxis;
+         double r=pos.Perp();
+         double z=pos.Z();
+         if((ix==0)&&(iy==0)) {
+            ri[0]=r;
+            ri[1]=r;
+            zi[0]=z;
+            zi[1]=z;
+         } else {
+            ri[0]=TMath::Min(r,ri[0]);
+            ri[1]=TMath::Max(r,ri[1]);
+            zi[0]=TMath::Min(z,zi[0]);
+            zi[1]=TMath::Max(z,zi[1]);
+         }
+      }
+   }
+   int isBarrel;
+   double x[2],y[2],dxMax;
+   if(ri[1]-ri[0]<zi[1]-zi[0]) {
+      // barrel
+      isBarrel=1;
+      x[0]=ri[0];
+      x[1]=ri[1];
+      y[0]=zi[0];
+      y[1]=zi[1];
+      dxMax=20.;
+   } else {
+      // endcap
+      isBarrel=0;
+      x[0]=zi[0];
+      x[1]=zi[1];
+      y[0]=ri[0];
+      y[1]=ri[1];
+      dxMax=10.;
+   }
+   size_t iMS;
+   for(iMS=0;iMS<m_moduleSetVector.size();iMS++) {
+      FTK_ModuleSet &moduleSet(m_moduleSetVector[iMS]);
+      if(moduleSet.m_isBarrel != isBarrel) continue;
+      double xmin=TMath::Min(x[0],moduleSet.m_x[0]);
+      double xmax=TMath::Max(x[1],moduleSet.m_x[1]);
+      if(xmax-xmin<=dxMax) {
+         moduleSet.m_x[0]=xmin;
+         moduleSet.m_x[1]=xmax;
+         moduleSet.m_dy=
+            TMath::Max(y[1]-y[0],moduleSet.m_dy);
+         moduleSet.m_modules.insert
+            (std::make_pair(0.5*(y[1]+y[0]),module));
+         break;
+      }
+   }
+   if(iMS==m_moduleSetVector.size()) {
+      // start a new FTK_ModuleSet
+      m_moduleSetVector.resize(iMS+1);
+      FTK_ModuleSet &moduleSet(m_moduleSetVector[iMS]);
+      moduleSet.m_isBarrel=isBarrel;
+      moduleSet.m_x[0]=x[0];
+      moduleSet.m_x[1]=x[1];
+      moduleSet.m_dy=y[1]-y[0];
+      moduleSet.m_modules
+         .insert(std::make_pair(0.5*(y[1]+y[0]),module));
+   }
+}
+
+void FTK_ModuleLocator::print(void) const {
+   std::cout<<"FTK_ModuleLocator::print "<<m_moduleSetVector.size()
+            <<" module sets\n";
+   for(size_t i=0;i<m_moduleSetVector.size();i++) {
+      FTK_ModuleSet const &moduleSet=m_moduleSetVector[i];
+      std::cout<<" moduleSet["<<i<<"] ";
+      if(moduleSet.m_isBarrel) {
+         std::cout<<"barrel R=[";
+      } else {
+         std::cout<<"endcap Z=[";
+      }
+      std::cout<<moduleSet.m_x[0]<<","<<moduleSet.m_x[1]
+               <<"] n(modules)="<<moduleSet.m_modules.size()
+               <<"\n";
+      for(std::multimap<double,FTK_ModuleGeometry const *>
+             ::const_iterator ix=moduleSet.m_modules.begin();
+          ix!=moduleSet.m_modules.end();) {
+         double z=(*ix).first;
+         if(moduleSet.m_isBarrel) {
+            std::cout<<"  Z=["<<z;
+         } else {
+            std::cout<<"  R=["<<z;
+         }
+         std::pair<
+         std::multimap<double,FTK_ModuleGeometry const *>::const_iterator,
+            std::multimap<double,FTK_ModuleGeometry const *>::const_iterator>
+            er=moduleSet.m_modules.equal_range(z);
+         for(ix=er.first;ix!=er.second;ix++) {
+            std::cout<<" "<<(*ix).second->m_id;
+         }
+         std::cout<<" ]\n";
+      }
+   }
+}
+
+FTKHit *FTK_ModuleLocator::locate(FTKTruthTrack const &track,
+                                  FTK_ModuleGeometry *ret_module) const {
+   static double const B_FACTOR=-0.3*2.083;
+   double rho=B_FACTOR/track.getPT()*track.getQ();
+   double cotTh=track.getPZ()/track.getPT();
+   double z0=track.getZ();
+   double d0=track.getD0();
+   double sinPhi=track.getPY()/track.getPT();
+   double cosPhi=track.getPX()/track.getPT();
+
+   std::multimap<double,std::pair<TVector2,FTK_ModuleGeometry const *> >
+      candidates;
+
+   for(size_t im=0;im<m_moduleSetVector.size();im++) {
+      /* std::cout<<" getCandidate moduleset["<<im<<"] rho="<<rho
+          <<" cotth="<<cotTh<<" z0="<<z0<<" d0="<<d0
+          <<" sinPhi="<<sinPhi<<" cosPhi="<<cosPhi<<"\n"; */
+      FTK_ModuleSet const &moduleSet=m_moduleSetVector[im];
+      moduleSet.getCandidates(rho,cotTh,z0,d0,sinPhi,cosPhi,
+                              candidates);
+   }
+   // select candidate with smallest s
+   FTKHit *r=0;
+   for(std::multimap<double,std::pair<TVector2,FTK_ModuleGeometry const *> >
+          ::const_iterator ii=candidates.begin();ii!=candidates.end();ii++) {
+      /*FTK_ModuleGeometry const *module=(*ii).second.second;
+       double s=module->m_center.Pt();
+       std::cout<<"  CAND hash="<<module->m_id
+                <<" cosphi(cent)="<<module->m_center[0]/s
+                <<" sinphi(cent)="<<module->m_center[1]/s
+                <<" track: "<<cosPhi<<" "<<sinPhi<<"\n"; */
+   }
+   if(candidates.begin()!=candidates.end()) {
+      TVector2 const &x=(*candidates.begin()).second.first;
+      FTK_ModuleGeometry const *module=(*candidates.begin()).second.second;
+      r=new FTKHit(module->m_isPixel ? 2 : 1);
+      r->setSector(module->m_hitSector);
+      r->setITkMode(FTKSetup::getFTKSetup().getITkMode());
+      r->setIdentifierHash(module->m_id);
+      r->setPhiWidth(1);
+      r->setEtaWidth(1);
+      r->setPlane(module->m_plane);
+      r->setCoord(0,(x.X()+module->m_width.X()*0.5)/module->m_pitch.X());
+      if(module->m_isPixel) {
+         r->setCoord(1,(x.Y()+module->m_width.Y()*0.5)/module->m_pitch.Y());
+      }
+      if(ret_module) *ret_module=*module;
+   }
+   return r;
+}
+
+void FTK_ModuleLocator::FTK_ModuleSet::getCandidates
+(double rho,double cotTh,double z0,double d0,double sinPhi0,double cosPhi0,
+ std::multimap <double,std::pair<TVector2,FTK_ModuleGeometry const *> >
+ &candidate) const {
+   // calculate coordinates along module extent
+   //   y = Z in barrel
+   //   y = R im endcap
+   double y[2];
+   for(int k=0;k<2;k++) {
+      if(m_isBarrel) {
+         // barrel m_x are Rmin and Rmax
+         double r=m_x[k];
+         double rrho=r*rho;
+         double s=r*(1.+rrho*rrho/24.);
+         y[k]=s*cotTh+z0;
+      } else {
+         double z=m_x[k];
+         double s=(z-z0)/cotTh;
+         double srho=s*rho;
+         y[k]=s*(1.-srho*srho/24.);
+      }
+   }
+   if(y[0]>y[1]) {
+      double yy=y[0];
+      y[0]=y[1];
+      y[1]=yy;
+   }
+   /*std::cout<<"  isBarrel="<<m_isBarrel<<" x[]="<<m_x[0]<<" "<<m_x[1]<<" y[]="<<y[0]<<" "<<y[1]<<"\n"; */
+
+   // loop over a range of modules
+   // start at module with smallest y where y>= y[0]-0.5*dy
+   for(std::multimap<double,FTK_ModuleGeometry const *>
+          ::const_iterator iModule=m_modules.lower_bound(y[0]-m_dy*0.5);
+       iModule!=m_modules.end();iModule++) {
+      // leave loop if
+      //   y> y[1]+0.5*dy
+      // because all following modules have even larger y
+      /*std::cout<<" check: "<<(*iModule).first<<" >= "<<(y[0]-m_dy*0.5)
+        <<" is: "<<(*iModule).first<<" ?<= "<<(y[1]+m_dy*0.5)<<"?"; */
+      if((y[1]+m_dy*0.5)<(*iModule).first) {
+         //std::cout<<" no\n";
+         break;
+      }
+      //std::cout<<" yes\n";
+      // here we have a module with 
+      //   y[0]-d/2<=y and y<=y[1]+d/2
+      // ->  y[0]<= y+d/2  and y[1]>=y-d/2
+      // the estimated extrapolated track yt, which is between y[0] and y[1]
+      // possibly is on the module [distance d/2 around the centre y].
+      FTK_ModuleGeometry const *module=(*iModule).second;
+
+      TVector2 x;
+      double s;
+      module->extrapolate(rho,cotTh,z0,d0,sinPhi0,cosPhi0,0,0,&x,&s);
+
+      // check whether coordinates are on the module
+      if(TMath::Abs(x.X())>0.5*module->m_width.X()) continue;
+      if(TMath::Abs(x.Y())>0.5*module->m_width.Y()) continue;
+      // add to the list of results
+      candidate.insert(std::make_pair(s,std::make_pair(x,module)));
+   }
+}
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRoot.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRoot.cxx
index 98ff740e18b8..b5f4be7559fe 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRoot.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRoot.cxx
@@ -1069,9 +1069,10 @@ void  FTKPattGenRoot::SetModuleGeometryCheck(const std::string &fileName,
                <<"select="<<" (undefined selection algorithm)\n";
          }
       } else {
+         Fatal("SetModuleGeometryCheck")
+            <<"module geometry "<<fileName<<" not found but select="
+            <<m_select<<"\n";
          m_select= RndSector;
-         Error("SetModuleGeometryCheck")
-            <<"module geometry "<<fileName<<" not found\n";
          Warning("SetModuleGeometryCheck")
             <<"revert to select="<<m_select
             <<": no boudary check, random sector selection\n";
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRootAlgo.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRootAlgo.cxx
index 1fa73d0505e6..409544c0e3ee 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRootAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKPattGenRootAlgo.cxx
@@ -209,9 +209,13 @@ StatusCode FTKPattGenRootAlgo::initialize() {
    ftkset.setIBLMode(m_IBLMode);
    ftkset.setfixEndcapL0(m_fixEndcapL0);
    ftkset.setITkMode(m_ITkMode);
+   log << MSG::INFO <<"HWMODEID="<<m_HWMODEID
+       <<" IBLMode="<<m_IBLMode<<" fixEndcapL0="<<m_fixEndcapL0
+       <<" ITKMode="<<m_ITkMode<<"\n";
+
    
    // --- Create the pmap file object
-   log << MSG::INFO << "RunPattGen() Make FTKPlaneMap." << endmsg;
+      log << MSG::INFO << "make FTKPlaneMap "<<m_pmap_path << endmsg;
    FTKPlaneMap* pmap = new FTKPlaneMap(m_pmap_path.c_str());
    if (!(*pmap)) {
       log << MSG::FATAL << "Error using plane map: " << m_pmap_path << endmsg;
@@ -219,34 +223,38 @@ StatusCode FTKPattGenRootAlgo::initialize() {
    }
 
    // --- Create region map object
-   log << MSG::INFO << "RunPattGen() Make FTKRegionMap." << endmsg;
+   log << MSG::INFO << "Make FTKRegionMap "<<m_rmap_path << endmsg;
    FTKRegionMap* rmap = new FTKRegionMap(pmap, m_rmap_path.c_str());
 
    if(m_HWMODEID==2) {
       if(m_modulelut_path.empty()) {
-         log << MSG::FATAL <<"RunPattGen() A module LUT is required when HW SS calculation is required"<<endmsg;
+         log << MSG::FATAL <<"A module LUT is required when HW SS calculation is required"<<endmsg;
 	 return StatusCode::FAILURE;
       } else {
+         log << MSG::INFO << "Load LUT "<<m_modulelut_path<<endmsg;
          rmap->loadModuleIDLUT(m_modulelut_path.c_str());
       }
    }
 
    // --- Create ssmap
    const bool force_am_hashmap = false;
-   log << MSG::INFO << "RunPattGen() Make FTKSSMap." << endmsg;
+   log << MSG::INFO << "Make FTKSSMap "<<m_ssmap_path << endmsg;
    FTKSSMap* ssmap = new FTKSSMap(rmap, m_ssmap_path.c_str(), force_am_hashmap);
 
    // --- Create the slices file object
-   log << MSG::INFO << "RunPattGen() Make FTKSectorSlice." << endmsg;
+   log << MSG::INFO << "Make FTKSectorSlice "
+       <<m_slices_path << endmsg;
    FTKSectorSlice* sectorslice = new FTKSectorSlice();
    sectorslice->loadSlices(m_slices_path);
 
    // --- create  FTKConstantBank
-   log << MSG::INFO << "RunPattGen() Make FTKConstantBank." << endmsg;
+   log << MSG::INFO << "Make FTKConstantBank "
+       <<m_fitconstants_path << endmsg;
    FTKConstantBank* constbank = new FTKConstantBank(pmap->getTotalDim(), m_fitconstants_path.c_str());
 
   // --- create pattgen object
-  log << MSG::INFO << "RunPattGen() Make FTKPattGenRoot."
+  log << MSG::INFO << "Make FTKPattGenRoot "
+      <<" keep7of8="<<m_keep7of8<<" tolerance7of8="<<m_tolerance7of8
       << endmsg;
 
   m_pattgen=new FTKPattGenRoot(m_curreg,ssmap,sectorslice,constbank,m_keep7of8,
@@ -255,20 +263,33 @@ StatusCode FTKPattGenRootAlgo::initialize() {
                                ,m_propagator
 #endif
                                );
-  log << MSG::INFO << "RunPattGen() beam spot at "
+  log << MSG::INFO << "beam spot at "
       <<m_beamspotX<<" "<<m_beamspotY
       << endmsg;
   m_pattgen->SetRandomNumberGenerator(m_rndmSvc->GetEngine(m_rndStreamName));
   m_pattgen->setBeamspot(m_beamspotX,m_beamspotY);
+  log << MSG::INFO << "Read sector path "<<m_sectors_path<<endmsg;
   m_pattgen->ReadSectorFile(m_sectors_path); // set sectors path
+  log<< MSG::INFO << "Slice parameters:"
+     <<" phi: "<<m_phi_min<<" "<<m_phi_max
+     <<" c: "<<m_c_min<<" "<<m_c_max
+     <<" d0: "<<m_d0_min<<" "<<m_d0_max
+     <<" z0: "<<m_z0_min<<" "<<m_z0_max
+     <<" eta: "<<m_eta_min<<" "<<m_eta_max
+     <<endmsg;
   m_pattgen->SetSliceParameters(m_phi_min,m_phi_max, m_c_min, m_c_max,
 			     m_d0_min, m_d0_max, m_z0_min, m_z0_max, m_eta_min, m_eta_max);
+  log<< MSG::INFO << "D0 exponent: "<<m_d0_alpha<<endmsg;
   m_pattgen->SetD0Exponent(m_d0_alpha);
+  log<< MSG::INFO <<"Overlap removal: "<<m_overlap<<endmsg;
   m_pattgen->SetOverlapRemoval(m_overlap);
+  log<<MSG::INFO <<"Module boundary check: "<<m_sectorSelection
+     <<" module position file: \""<<m_ModuleGeometryFile<<"\""<<endmsg;
   m_pattgen->SetModuleGeometryCheck
      (m_ModuleGeometryFile,(FTKPattGenRoot::SectorSelection)m_sectorSelection);
 
   // open output file
+  log<<MSG::INFO <<"Output file: "<<m_OutputFile<<endmsg;
   m_pattgen->SetRootOutput(m_OutputFile); 
 
   return StatusCode::SUCCESS;
@@ -305,11 +326,12 @@ StatusCode FTKPattGenRootAlgo::finalize() {
 
 
 void FTKPattGenRootAlgo::PostMessage(void) {
-   if     (FTKLogger::m_type==0)  ATH_MSG_FATAL(m_buffer->str());
-   else if(FTKLogger::m_type==1)  ATH_MSG_ERROR(m_buffer->str());
-   else if(FTKLogger::m_type==2)  ATH_MSG_WARNING(m_buffer->str());
-   else if(FTKLogger::m_type==3)  ATH_MSG_INFO(m_buffer->str());
-   else if(FTKLogger::m_type==4)  ATH_MSG_DEBUG(m_buffer->str());
+   int fType=getLoggerMsgType();
+   if     (fType==0)  ATH_MSG_FATAL(getLoggerMsg());
+   else if(fType==1)  ATH_MSG_ERROR(getLoggerMsg());
+   else if(fType==2)  ATH_MSG_WARNING(getLoggerMsg());
+   else if(fType==3)  ATH_MSG_INFO(getLoggerMsg());
+   else if(fType==4)  ATH_MSG_DEBUG(getLoggerMsg());
 }
 
 
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKSectorSlice.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKSectorSlice.cxx
index b88b58d868a7..f1b47f297e04 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/FTKSectorSlice.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/FTKSectorSlice.cxx
@@ -237,25 +237,41 @@ vector<int>* FTKSectorSlice::searchSectors(FTKTrack& track) {
 
   int error=0;
 
+  static int print=200;
   if ((track.getPhi()<m_phi_min) || (track.getPhi()>m_phi_max)) {
-    cout << "Error: wrong phi parameter " << track.getPhi() << '\n';
+     if(print) {
+        cout << "Error: wrong phi parameter " << track.getPhi() << '\n';
+        print--;
+     }
     error++;
   }
   if ((2.*track.getHalfInvPt()<m_c_min) ||
       (2.*track.getHalfInvPt()>m_c_max)) {
-    cout << "Error: wrong c parameter " << 2.*track.getHalfInvPt() << '\n';
+     if(print) {
+        cout << "Error: wrong c parameter " << 2.*track.getHalfInvPt() << '\n';
+        print--;
+     }
     error++;
   }
   if ((track.getIP()<m_d0_min) || (track.getIP()>m_d0_max)) {
-    cout << "Error: wrong d0 parameter " << track.getIP() << '\n';
+     if(print) {
+        cout << "Error: wrong d0 parameter " << track.getIP() << '\n';
+        print--;
+     }
     error++;
   }
   if ((track.getZ0()<m_z0_min) || (track.getZ0()>m_z0_max)) {
-    cout << "Error: wrong z0 parameter " << track.getZ0() << '\n';
+     if(print) {
+        cout << "Error: wrong z0 parameter " << track.getZ0() << '\n';
+        print--;
+     }
     error++;
   }
   if ((track.getCotTheta()<m_ctheta_min) || (track.getCotTheta()>m_ctheta_max)) {
-    cout << "Error: wrong ctheta parameter " << track.getCotTheta() << '\n';
+     if(print) {
+        cout << "Error: wrong ctheta parameter " << track.getCotTheta() << '\n';
+        print--;
+     }
     error++;
   }
   //if(error) exit(0);
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/PattMergeRootAlgo.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/PattMergeRootAlgo.cxx
index 4ccc77b5d1e2..cd4dbc7b0443 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/PattMergeRootAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/PattMergeRootAlgo.cxx
@@ -158,11 +158,12 @@ StatusCode PattMergeRootAlgo::RunMerging() {
 
 
 void PattMergeRootAlgo::PostMessage(void) {
-   if(FTKLogger::m_type==0)  ATH_MSG_FATAL(m_buffer->str());
-   else if(FTKLogger::m_type==1)  ATH_MSG_ERROR(m_buffer->str());
-   else if(FTKLogger::m_type==2)  ATH_MSG_WARNING(m_buffer->str());
-   else if(FTKLogger::m_type==3)  ATH_MSG_INFO(m_buffer->str());
-   else if(FTKLogger::m_type==4)  ATH_MSG_DEBUG(m_buffer->str());
+   int fType=getLoggerMsgType();
+   if     (fType==0)  ATH_MSG_FATAL(getLoggerMsg());
+   else if(fType==1)  ATH_MSG_ERROR(getLoggerMsg());
+   else if(fType==2)  ATH_MSG_WARNING(getLoggerMsg());
+   else if(fType==3)  ATH_MSG_INFO(getLoggerMsg());
+   else if(fType==4)  ATH_MSG_DEBUG(getLoggerMsg());
 }
 
 
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_entries.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_entries.cxx
index 57ca94938d27..1d5aa7b61e9a 100644
--- a/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_entries.cxx
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_entries.cxx
@@ -1,18 +1,17 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
 #include "TrigFTKBankGen/FTKBankGenAlgo.h"
 #include "TrigFTKBankGen/FTKConstGenAlgo.h"
-
 #include "TrigFTKBankGen/PattMergeRootAlgo.h"
-
 #include "TrigFTKBankGen/FTKPattGenRootAlgo.h"
-
 #include "TrigFTKBankGen/FTKCachedBankGenAlgo.h"
+#include "TrigFTKBankGen/FTKDataMatrixFromMCAlgo.h"
 
 DECLARE_COMPONENT( FTKBankGenAlgo )
 DECLARE_COMPONENT( FTKConstGenAlgo )
-
 DECLARE_COMPONENT( PattMergeRootAlgo )
-
 DECLARE_COMPONENT( FTKPattGenRootAlgo )
-
 DECLARE_COMPONENT( FTKCachedBankGenAlgo )
-
+DECLARE_COMPONENT(FTKDataMatrixFromMCAlgo)
diff --git a/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_load.cxx b/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_load.cxx
new file mode 100644
index 000000000000..156d43e6928f
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKBankGen/src/components/TrigFTKBankGen_load.cxx
@@ -0,0 +1,6 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES(TrigFTKBankGen)
diff --git a/Trigger/TrigFTK/TrigFTKPool/src/FTKTrackFitterStats_p1.cxx b/Trigger/TrigFTK/TrigFTKPool/src/FTKTrackFitterStats_p1.cxx
index 0ce7ef1e4550..8de00f57c0b8 100644
--- a/Trigger/TrigFTK/TrigFTKPool/src/FTKTrackFitterStats_p1.cxx
+++ b/Trigger/TrigFTK/TrigFTKPool/src/FTKTrackFitterStats_p1.cxx
@@ -5,9 +5,6 @@
 #include "TrigFTKPool/FTKTrackFitterStats_p1.h"
 
 FTKTrackFitterStats_p1::FTKTrackFitterStats_p1() :
-  m_ncombs(0), m_nfits(0), m_nfits_maj(0),
-  m_nfits_maj_pix(0),
-  m_nfits_maj_SCT(0),
-  m_nfits_rec(0), m_nfits_addrec(0),
+  m_ncombs(0), m_nfits(0), m_nfits_maj(0), m_nfits_maj_pix(0), m_nfits_maj_SCT(0), m_nfits_rec(0), m_nfits_addrec(0),
   m_nfits_bad(0), m_nfits_rej(0), m_nfits_badmaj(0), m_nfits_rejmaj(0)
 {}
diff --git a/Trigger/TrigFTK/TrigFTKSim/CMakeLists.txt b/Trigger/TrigFTK/TrigFTKSim/CMakeLists.txt
index e97452bb881f..a20da4ce2e8e 100644
--- a/Trigger/TrigFTK/TrigFTKSim/CMakeLists.txt
+++ b/Trigger/TrigFTK/TrigFTKSim/CMakeLists.txt
@@ -77,7 +77,8 @@ atlas_add_library( TrigFTKSimLib
                    src/FTKSetup.cxx
                    src/PatternBank.cxx
                    src/FTK_AMBank.cxx
-                   src/atlClustering.cxx
+                   src/FTKClusteringPrintout.cxx
+                   src/FTKClusteringEngine.cxx
                    src/FTKRoadFileOutput.cxx
                    src/FTKConstantBank.cxx
                    src/FTKTrackInput.cxx
@@ -115,6 +116,9 @@ atlas_add_library( TrigFTKSimLib
                    src/FTKRootFile.cxx
                    src/FTKMergeRoot.cxx
                    src/FTK_AMsimulation_base.cxx
+                   src/FTK_HitMask.cxx
+                   src/FTK_CompressedPatternList.cxx
+                   src/FTK_CompressedSectorPatternList.cxx
                    src/FTK_CompressedAMBank.cxx
                    src/FTKSteering.cxx
                    ${TrigFTKSimLibDictSource}
@@ -140,17 +144,32 @@ atlas_add_executable( trigftk_efficiency
                       INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}
                       LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${HEPPDT_LIBRARIES} ${EIGEN_LIBRARIES} ${HEPMC_LIBRARIES} ${TBB_LIBRARIES} AthenaBaseComps PileUpToolsLib StoreGateLib SGtests GaudiKernel InDetIdentifier InDetReadoutGeometry InDetPrepRawData Particle TrkParameters TrkParticleBase TrkTrack TrkTruthData TrkExInterfaces TrkToolInterfaces TrigInDetEvent TrigFTKPool IdDictDetDescr EventInfo NavFourMom GeneratorObjects InDetRawData InDetSimData TrkMeasurementBase TrkRIO_OnTrack TrigFTKSimLib )
 
+atlas_add_executable( trigftk_efficiency_step_by_step
+                      standalone/efficiency_step_by_step.cc
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${HEPPDT_LIBRARIES} ${EIGEN_LIBRARIES} ${HEPMC_LIBRARIES} ${TBB_LIBRARIES} AthenaBaseComps PileUpToolsLib StoreGateLib SGtests GaudiKernel InDetIdentifier InDetReadoutGeometry InDetPrepRawData Particle TrkParameters TrkParticleBase TrkTrack TrkTruthData TrkExInterfaces TrkToolInterfaces TrigInDetEvent TrigFTKPool IdDictDetDescr EventInfo NavFourMom GeneratorObjects InDetRawData InDetSimData TrkMeasurementBase TrkRIO_OnTrack TrigFTKSimLib )
+
 atlas_add_executable( trigftk_dataflow
                       standalone/dataflow.cc
                       INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}
                       LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${HEPPDT_LIBRARIES} ${EIGEN_LIBRARIES} ${HEPMC_LIBRARIES} ${TBB_LIBRARIES} AthenaBaseComps PileUpToolsLib StoreGateLib SGtests GaudiKernel InDetIdentifier InDetReadoutGeometry InDetPrepRawData Particle TrkParameters TrkParticleBase TrkTrack TrkTruthData TrkExInterfaces TrkToolInterfaces TrigInDetEvent TrigFTKPool IdDictDetDescr EventInfo NavFourMom GeneratorObjects InDetRawData InDetSimData TrkMeasurementBase TrkRIO_OnTrack TrigFTKSimLib )
 
+atlas_add_executable( trigftk_makeconn
+                      standalone/make_conn.cc
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${HEPPDT_LIBRARIES} ${EIGEN_LIBRARIES} ${HEPMC_LIBRARIES} ${TBB_LIBRARIES} AthenaBaseComps PileUpToolsLib StoreGateLib SGtests GaudiKernel InDetIdentifier InDetReadoutGeometry InDetPrepRawData Particle TrkParameters TrkParticleBase TrkTrack TrkTruthData TrkExInterfaces TrkToolInterfaces TrigInDetEvent TrigFTKPool IdDictDetDescr EventInfo NavFourMom GeneratorObjects InDetRawData InDetSimData TrkMeasurementBase TrkRIO_OnTrack TrigFTKSimLib )
+
+atlas_add_executable( trigftk_makecompressedbank
+                      standalone/makecompressedbank.cc
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${HEPPDT_LIBRARIES} ${EIGEN_LIBRARIES} ${HEPMC_LIBRARIES} ${TBB_LIBRARIES} AthenaBaseComps PileUpToolsLib StoreGateLib SGtests GaudiKernel InDetIdentifier InDetReadoutGeometry InDetPrepRawData Particle TrkParameters TrkParticleBase TrkTrack TrkTruthData TrkExInterfaces TrkToolInterfaces TrigInDetEvent TrigFTKPool IdDictDetDescr EventInfo NavFourMom GeneratorObjects InDetRawData InDetSimData TrkMeasurementBase TrkRIO_OnTrack TrigFTKSimLib )
+
 # Install files from the package:
 atlas_install_python_modules( python/__init__.py python/TrigFTKTruthAlgsConfig.py python/QueryFTKdb.py python/findInputs.py python/FTKSimOptions.py )
 atlas_install_joboptions( share/*.py )
 atlas_install_joboptions( share/skeleton.*.py )
 atlas_install_runtime( scripts/*_tf.py )
-atlas_install_runtime( test/TrigFTKSim_TestConfiguration.xml scripts/rtt_compare.py scripts/TrigFTKSM4Un_tf.py scripts/TrigFTKTM64SM4Un_tf.py scripts/TrigFTKSimITk_tf.py )
+atlas_install_runtime( test/TrigFTKSim_TestConfiguration.xml scripts/rtt_compare.py scripts/TrigFTKSM4Un_tf.py standalone/plot_simple_dataflow.C scripts/TrigFTKTM64SM4Un_tf.py scripts/TrigFTKSimITk_tf.py )
 atlas_install_generic( config/map_file/*
                        DESTINATION share/ftk_configuration/map_files
                        EXECUTABLE )
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringEngine.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringEngine.h
new file mode 100644
index 000000000000..e00fa9497180
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringEngine.h
@@ -0,0 +1,317 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FTKCLUSTERINGENGINE_H
+#define FTKCLUSTERINGENGINE_H
+
+#include "TrigFTKSim/ftktypes.h"
+#include "TrigFTKSim/FTKClusteringPrintout.h"
+#include "TrigFTKSim/FTKLogging.h"
+
+#define GRID_ROW_MAX 21
+#define GRID_COL_MAX 8
+#define hitRowInGrid(gridCntRow, hit) ((hit->getPhiSide() <= gridCntRow + GRID_ROW_MAX/2) && \
+        (hit->getPhiSide() >= gridCntRow - GRID_ROW_MAX / 2))? true : false
+#define hitColInGrid(gridStrCol, hit) (hit->getEtaStrip() < gridStrCol + GRID_COL_MAX)? true : false
+
+#include <ctype.h>
+#include <vector>
+#include <set>
+#include <map>
+#include <memory>
+#include <boost/circular_buffer.hpp>
+
+typedef std::vector<std::unique_ptr<FTKRawHit>> hitVector;
+typedef std::map<uint32_t, hitVector> hitsByModuleMap;
+
+
+class cluster {
+public:
+    hitVector hitlist; //< list of hits that make the cluster
+    FTKRawHit clusterEquiv; //< hit equivalent to the cluster
+    FTKRawHit seed; //< The first hit, which is used to start the cluster in PCM > 100
+    bool isSafe; // confirmed by ganged pattern recognition
+    bool isKilled; // ganged pattern recognition suggest to remove this cluster
+
+  ~cluster();
+};
+
+
+typedef std::vector<std::unique_ptr<cluster>> cluList;
+typedef std::map<uint32_t, cluList> clustersByModuleMap;
+
+/**
+ * This class creates a hit whose coordinates are relative to the Front-End chip
+ * of the module that it belongs to. It is used for the correct ordering of the hits
+ * in the FTK_IM hit decoder.
+ */
+class FTK_FECoordsHit {
+public:
+    /**
+     * Create an FTK_Hit_FECoords from an FTKRawHit
+     * \param h FTKRawHit to be processed
+     */
+    FTK_FECoordsHit(const FTKRawHit& hit) {
+        tot = hit.getTot();
+        int acol = hit.getEtaStrip();
+        int arow = hit.getPhiSide();
+        bool isIBLmodule = (hit.getModuleType() == ftk::MODULETYPE_IBL_PLANAR || hit.getModuleType() == ftk::MODULETYPE_IBL3D);
+	//The relative coordinates are different for pixel and IBL, 
+        if(!isIBLmodule){
+            if (arow < ftk::clustering::rowsInFEChipPerPixelModuleRow) {
+                fe = ftk::clustering::feChipsInRowPixel + acol/ftk::clustering::colsInFEChipPerPixelModuleRow;
+                lrow = arow;
+                lcol = acol%ftk::clustering::colsInFEChipPerPixelModuleRow;
+            } else {
+                fe = (ftk::clustering::feChipsInRowPixel - 1) - acol/ftk::clustering::colsInFEChipPerPixelModuleRow; //-1 because we start counting from 0
+                lrow = (ftk::numberOfPhiPixelsInPixelModule - 1) - arow; //We start counting from 0
+                lcol = (ftk::clustering::colsInFEChipPerPixelModuleRow - 1) - acol%ftk::clustering::colsInFEChipPerPixelModuleRow; //Start counting from 0
+            }
+        }else{
+            if (acol < ftk::clustering::colsInFEChipPerIblModuleRow) {
+                fe = 0;
+                lcol = acol;
+            } else {
+                fe = 1;
+                lcol = acol-ftk::clustering::colsInFEChipPerIblModuleRow;
+            }
+            lrow = (ftk::clustering::rowsInFEChipPerIblModuleRow - 1) - arow;
+        }
+    }
+
+    int fe; ///< The FE chip of the hit
+    int tot; ///< ToT of the hit
+    int lcol; ///< Column of the hit expressed in FE coordinates
+    int lrow; ///< Row of the hit expressed in FE coordinates
+};
+
+
+class FTKClusteringEngine : FTKLogging
+{
+private:
+
+    bool m_saveClusterContent;
+    bool m_diagClustering; //!< If true. clusters are allowed to be connected only by diagonal pixels
+    bool m_sctClustering; //!< If true, sct hits are also clustered
+    bool m_ibl3DRealistic; //!<If true, you can get the same IBL 3D centorid as the FTK_IM FW.
+    bool m_duplicateGanged; //!< If true, if a ganged pixel is hit, its partner is selected as an active hit
+    bool m_gangedPatternRecognition; //!< The code contains functions that allow for some "smart"
+				   //!< recognition on which hits are the "real" ones and which are
+                                   //!< and which are fake. If true, this test is enabled.
+    bool m_splitBlayerModules;
+    int m_pixelClusteringMode; //!< Which clustering mode to use. 
+
+    static bool sortPixelInput (const std::unique_ptr<FTKRawHit>& i, const  std::unique_ptr<FTKRawHit>& j);
+    static bool sortIBLInput(const std::unique_ptr<FTKRawHit>& i, const std::unique_ptr<FTKRawHit>& j);
+
+    /*!
+    * Function that examines if a cluster is in contact with the sliding window borders
+    * @param Cluster to be examined
+    * @return true if the cluster is in contact with the borders, false otherwise
+    */
+    bool isSplitCluster(const cluster* clu);
+
+    /*!
+    * Function that examines if a hit belongs in an IBL module
+    * @param Hit to be examined
+    * @return true if the hit is on an IBL module, false otherwise
+    */
+    bool hitOnIBLmodule(const FTKRawHit &hit);
+
+    /*!
+    * Function that finds the HashID of the module for a given hit. 
+    * @param Hit to be examined
+    * @return a HashID. 
+    */
+    uint32_t getModuleId(const FTKRawHit &hit);
+
+    /*!
+    * Function that replicates the Pixel & IBL decoder. It is bit-accurate
+    * with the firmware implementation. More details can be found in the FTK_IM 
+    * documentation.
+    * @param Vector of hits that have to be sorted.
+    */
+    void realisticPixelDecoder(hitVector& currentHits);
+
+
+    /*!
+    * Function that examines whether two hits share a border. If diagClustering is true, 
+    * it counts as neighbours also diagonal hits. 
+    * @param hit1 A hit
+    * @param hit2 Well, the other hit
+    * @return true if hits are in contact
+    */
+    bool neighborhood(const FTKRawHit &hit1, const FTKRawHit &hit2);
+
+    /*!
+    * Function that examines whether two hits share a border. If diagClustering is true, 
+    * it counts as neighbours also diagonal hits. 
+    * @param hit1 A hit
+    * @param hit2 Well, the other hit
+    * @return true if hits are in contact
+    */
+
+    /*!
+    * Recursively adds hits to a given cluster.
+    * If no cluster is given (or empty cluster) make a cluster out of the 1st hit.
+    * @param currentHits the hits from which the cluster will be formed
+    * @param the cluster
+    * @return the number of hits in the final cluster
+    */
+    int buildUpCluster(hitVector& currentHits, cluster& clu);
+
+    /*!
+    * Group all hits form one module into clusters. 
+    * It is the default clustering implementation for SCT and it does not use the Sliding 
+    * window mechanism. 
+    * @param currentHits the hits that have to be clustered. 
+    * @param currentClusters the vector holding the clulsters which have been created
+    */
+    void makeClustersLNF(hitVector& currentHits, cluList& currentClusters);
+
+    /*!
+    * Group all hits form one module into clusters. 
+    * This implementation uses the Sliding window mechanism, replicating the FW iplementation. 
+    * @param currentHits the hits that have to be clustered. 
+    * @param currentClusters the vector holding the clulsters which have been created
+    */
+    void makeClustersGridWindow(hitVector& currentHits, cluList& currentClusters);
+
+    /*!
+    * Function that replicates the sliding window mechanism. For more details about the 
+    * implementation, please see the FTK_IM documentation. 
+    * @param cb the circular buffer containing hits
+    * @param fifo another hit container
+    * @param gridHits a vector with the hits of inside the window.  
+    * @return The hit that the cluster will be formed around. 
+    */
+    FTKRawHit gridAUTH( boost::circular_buffer<std::unique_ptr<FTKRawHit>> &cb,
+                                         hitVector &fifo, hitVector &gridhits);
+    /*!
+    * Function creating a cluster around a given hit (the seed).
+    * @param currentHits the hits from which the cluster will be formed 
+    * @param currentClusters vector which will hold the cluster
+    * @param seed the hit around which the cluster will be formed
+    */
+    void makeClusterFromSeed(hitVector& currentHits, cluList& currentClusters, FTKRawHit& seed);
+
+    /*!
+    * Function calculating the central position of the cluster (i.e. the centroid) for all possible
+    * scenarios (SCT, Pixel, IBL). During the execution of this function, the
+    * following variables are set for each cluster: X, Y, Z,
+    *
+    * \param cluster the cluster whose average is going to be calculated
+    */
+    void averageCluster(std::unique_ptr<cluster>& clu);
+
+    /*!
+    * Function examining whether the a given row has ganged pixels
+    * \param the row to be examined
+    * \return true if the row has ganged pixels, false otherwise
+    */
+    bool pixelRowIsGanged(const int row);
+
+    /*! 
+    * Function which finds the partner of a ganged pixel
+    * @param hit The hit 
+    * @return the row of the ganged partner
+    */
+    int gangedPartner(const FTKRawHit &);
+
+    /*!
+    * Function examining if a hit is ganged. In case the hit belongs to a pixel
+    * module and at a row with ganged pixels, the phi coordinate of the pixel is
+    * returned. It always returns 0 if the hit belongs to an IBL module.
+    * \param hit hit to be examined
+    * \return The phi coordinate of the hit if the hit is ganged, 0 otherwise
+    */
+    int hitIsGanged(const FTKRawHit &);
+   
+    /*! 
+    * Function which examines whether a hit that belongs to a ganged pixel 
+    * has a neighbouring hit. This is used in the smart ganged partner recognition
+    * @param hit The hit 
+    * @param cluster The cluster to be examined
+    * @param connectedHits list of ganged hits that are connected to a confirmed ganged hit
+    * @return true if the ganged hit has a neighboor, false otherwise
+    */
+    bool gangedHitHasNeighborhood(const FTKRawHit &hit, const cluster* clu, hitVector &connectedHits);
+
+    
+    /*! 
+    * Function which finds the hits that are in contact with a ganged pixel. 
+    * @param cluster The cluster to be examined
+    * @param connectedHits list of ganged hits that are connected to a confirmed ganged hit
+    * @return true if the ganged hit has connected hits
+    */
+    bool findConnectedGanged(const std::unique_ptr<cluster> &clu, hitVector &connectedHits);
+
+    /*!
+    * Function which examines whether the ganged pattern recognition suggest the cluster removal
+    * @param cluster The cluster to be examined
+    * @param connectedHits list of ganged hits that are connected to a confirmed ganged hit
+    * @return true if the cluster should be removed, false otherwise
+    */
+    bool isKilled(const std::unique_ptr<cluster> &clu, const hitVector &connectedHits);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    double getDeltaX1A(const cluster* clu);
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    double getDeltaX2A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaXEC1A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaXEC2A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaYEC1A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaYEC2A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaY1A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaY2A(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaY1B(const cluster* clu);
+
+    /*! 
+    * Function used in PCM200, to be reimplemented
+    */
+    int getDeltaY2B(const cluster* clu);
+
+public:
+    FTKClusteringEngine();
+    FTKClusteringEngine(bool saveClusterContent, bool diagClustering,
+			bool sctClustering, bool ibl3DRealistic,
+                        bool duplicateGanged, bool gangedPatternRecognition,
+			bool splitBlayerModules, int pixelClusteringMode);
+    void atlClusteringBlayer(std::vector<FTKRawHit> &);
+    void atlClusteringLNF(std::vector<FTKRawHit> &);
+};
+
+#endif // FTKCLUSTERINGENGINE_H
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringPrintout.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringPrintout.h
new file mode 100644
index 000000000000..0121675d4bf2
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKClusteringPrintout.h
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FTKCLUSTERINGPRINTOUT_H
+#define FTKCLUSTERINGPRINTOUT_H
+
+#include "TrigFTKSim/FTKRawHit.h"
+#include "TrigFTKSim/ftkdefs.h"
+#include <map>
+#include <memory>
+class cluster;
+
+typedef std::vector<std::unique_ptr<FTKRawHit>> hitVector;
+typedef std::map<unsigned int, hitVector> hitsByModuleMap;
+typedef std::vector<std::unique_ptr<cluster>> cluList;
+typedef std::map<unsigned int, cluList> clustersByModuleMap;
+
+/**
+ * This class creates a hit whose coordinates are relative to the hit's position
+ * in the cluster. It is used to calculate if a cluster is split and for
+ * printing out the test vectors.
+ */
+class FTK_ClusterCoordHit
+{
+public:
+    /**
+     * Create an FTK_Hit_FECoords from an FTKRawHit
+     * \param h FTKRawHit to be processed
+     * \param seed the central hit of the cluster
+     */
+    FTK_ClusterCoordHit(const FTKRawHit &h, const FTKRawHit& seed) {
+        tot = h.getTot();
+        crow = h.getPhiSide() - (seed.getPhiSide() - 10);
+        if (seed.getEtaStrip() %2 != 0) ccol = h.getEtaStrip() - (seed.getEtaStrip() - 1);
+        else  ccol = h.getEtaStrip() - (seed.getEtaStrip());
+    }
+    int tot; ///<  ToT of the hit in the cluster
+    int ccol; ///< Column of the hit in the cluster
+    int crow; ///< Row of the hit in the cluster
+};
+
+
+
+class FTKClusteringPrintout
+{
+
+public:
+    FTKClusteringPrintout cp();
+    void printHitlist(const hitVector& currentHits);
+    void printCentroidList(clustersByModuleMap clustersByModule);
+    void printClusterList(clustersByModuleMap clustersByModule);
+    void printCluster(const std::unique_ptr<cluster> &clu);
+    void printHit(const FTKRawHit &hit);
+private:
+    bool clusterSort (const FTK_ClusterCoordHit &i, const FTK_ClusterCoordHit &j);
+
+
+};
+
+#endif
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKConstantBank.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKConstantBank.h
index be82bb5a03ff..6fe472a3afda 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKConstantBank.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKConstantBank.h
@@ -51,20 +51,22 @@ private:
   double ***m_maj_kk; //!
   double ***m_maj_invkk; //!
   
+  std::pair<int,int> **m_temp; //!
   // alternative constant vectors to be used when performing fits with integer precision
   // to match firmware specs -- these are not yet initialized anywhere!
   signed long long ***m_kernel_aux; //[m_nsectors][m_nconstr][m_ncoords] covariance matrix
   signed long long ***m_kernel_hw;  //[m_nsectors][m_nconstr][m_ncoords] covariance matrix
   signed long long **m_kaverage_aux; //[m_nsectors][m_nconstr] 
   signed long long ***m_maj_invkk_aux; //!
-  signed long long ***m_maj_invkk_hw; //!
+  int ***m_maj_invkk_hw; //!
   short int ***m_maj_invkk_pow; //!
-  short int ***m_maj_invkk_pow_hw; //!
+  int ***m_maj_invkk_pow_hw; //!
 
   double m_dTIBL; // dT (in K) for IBL compared to reference. For use in correcting for IBL bowing in x(phi) direction
 
   // function to model behavior of arithmetic shift register, used in firmware tests
   signed long long aux_asr(signed long long input, int shift, int width, bool &overflow) const;
+  signed int UnsignedToSigned(unsigned x) const;
 
 public:
   FTKConstantBank();
@@ -85,18 +87,19 @@ public:
   float getKernel( int isec , int iconstr , int icoord ) { return m_kernel[isec][iconstr][icoord]; }
   float *getKaverage(int sectid) const { return m_kaverage[sectid]; }
   float **getKernel(int sectid) const { return m_kernel[sectid]; }
+  std::pair<int, int> getFloating(double input); //Rui's change to match fw
 
   void setdTIBL(double t) {m_dTIBL = t;}
   double getdTIBL() {return m_dTIBL;}
 
   void doAuxFW(bool a);
 
-  static const int KAVE_SHIFT = 6; // 6
+  static const int KAVE_SHIFT = 4; // 6 //Rui's change to match fw
 
   static const int KERN_SHIFT = KAVE_SHIFT + 7;
   static const int EFF_SHIFT  = KERN_SHIFT + 3; // aux coordinates 8x larger
 
-  static const int KERN_SHIFT_HW = KAVE_SHIFT + 7;
+  static const int KERN_SHIFT_HW = KAVE_SHIFT + 8;//6; //Rui
   static const int EFF_SHIFT_HW  = KERN_SHIFT_HW + 3;
 
   static const int FIT_PREC   = 18; // 18
@@ -104,7 +107,8 @@ public:
 
   const int   const_plane_map[11] = {0, 0, 1, 1, 2, 2, 3, 4, 5, 6, 7};
   const int   const_coord_map[11] = {0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0};
-  const float const_scale_map[11] = {1, 8/16.88, 1, 8/16.88, 1, 8/16.88, 4, 4, 4, 4, 4};
+  const float const_scale_map[11] = {1, 16/16.88, 1, 16/16.88, 1, 16/16.88, 1, 1, 1, 1, 1}; //Rui's change to match fw
+  const float const_scale_map1[11] = {2, 1, 2, 1, 2, 1, 8, 8, 8, 8, 8}; //Rui's change to match fw
   // const float const_scale_map[11] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
 
   //   const double zIBL[20] = {-322.8975,301.7925,280.6875,259.5825,228.2775,186.7725,145.2675,103.7625,62.2575,20.7525,
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKDataInput.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKDataInput.h
index 67aa0ece810b..efd800fbf031 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKDataInput.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKDataInput.h
@@ -15,6 +15,7 @@
 #include "TrigFTKSim/FTKRoad.h"
 #include "TrigFTKSim/FTKRoadInput.h"
 #include "TrigFTKSim/FTKTrack.h"
+#include "TrigFTKSim/FTKClusteringEngine.h"
 #include "StoreGate/StoreGateSvc.h"
 
 #include <vector>
@@ -50,7 +51,6 @@ protected:
   StoreGateSvc*  m_storeGate;
   StoreGateSvc*  m_detStore;
   StoreGateSvc*  m_evtStore;
-  
   std::vector<FTKRawHit> m_original_hits; // global list of raw hits
   std::vector<FTKRawHit> **m_original_reghits; // local list of hits, RMAP applied
   std::vector<FTKTruthTrack> m_truth_track; // list of raw hits
@@ -89,6 +89,9 @@ protected:
   // These roads are stored in FTKRoadStream in root output of road_merger
   FTKRoadInput **m_roadinput;
 
+  //Class handling the clustering process
+  FTKClusteringEngine* m_clusteringEngine;
+
   // Additional information for Naoki's studies
   int m_nao_nhits_tot;             // total number of hits per event
   int m_nao_nclus_tot;             // total number of hits per event
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKLogging.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKLogging.h
index 485e61ccc176..a607162f5da1 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKLogging.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKLogging.h
@@ -66,6 +66,8 @@ protected:
    virtual ~FTKLogger();
    static void SetLogger(FTKLogger *ftkLogger);
    void SetType(int type,int printLevel,int abortLevel);
+   int getLoggerMsgType(void) const { return m_type; }
+   std::string getLoggerMsg(void) const { return m_buffer->str(); }
    //FTKLogger() : fLevel(0) { }
    virtual std::streamsize xsputn ( const char * s, std::streamsize n ); 
    virtual int overflow (int c);
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKPatternBySector.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKPatternBySector.h
index b665383e0178..67cc9e1539a5 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKPatternBySector.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKPatternBySector.h
@@ -79,6 +79,7 @@ class FTKPatternBySectorReader : public virtual FTKPatternBySectorBase {
    // read patterns (optimized IO), given a minimum number of patterns
    // repeated calls to this function will result in all sectors to be read
    // for sectors appended to the list, all patterns have been read
+   // i.e. the next call with return different sectors or an empty list
    // (use Rewind() to start all over)
    //   returns: next sector to read (or -1)
    virtual int ReadRaw(int firstSector,
@@ -141,7 +142,7 @@ class FTKPatternBySectorWriter : public virtual FTKPatternBySectorBase {
       (TDirectory &dir,WRITERTYPE_t type=kWriterDefault);
    // append patterns from file (down to minCoverage)
    //  the default algorithm merges one sector a time, calling
-   //    AppendMergedPatterns() fro each sector.
+   //    AppendMergedPatterns() for each sector.
    //    This procedure is not optimal for all file formats
    //  For this reason the method is virtual, to allow for
    //    a more efficient implementation
@@ -164,7 +165,7 @@ class FTKPatternBySectorWriter : public virtual FTKPatternBySectorBase {
    virtual int AppendMergedPatternsSector
       (int sector,FTKPatternOneSectorOrdered const *ordered);
    TDirectory &m_dir;
-   static const uint64_t PATTERN_CHUNK;
+   static const uint64_t s_pattern_chunk=20000000;
 };
 
 class FTKPatternBySectorForestWriter : public FTKPatternBySectorWriter {
@@ -177,6 +178,7 @@ public:
    virtual int AppendMergedPatternsSector(int sector,
                                     FTKPatternOneSectorOrdered const *ordered);
    typedef std::map<int,FTKPatternRootTree *> PatternTreeBySectorRW_t;
+
    PatternTreeBySectorRW_t m_patterns;
 };
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRawHit.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRawHit.h
index 1e68d8cf5a25..c17fd6c4d831 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRawHit.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRawHit.h
@@ -257,7 +257,6 @@ public:
   const float IBL_3D_column_scaling =
     (10*ftk::lengthOfIblModuleIn250umPixels)/ftk::numberOfEtaPixelsInIblModule; // (10*163.2)/160);
 
-
   ClassDef(FTKRawHit,4)
 };
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRoadFinderAlgo.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRoadFinderAlgo.h
index ef61ec1005a3..174c7296626e 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRoadFinderAlgo.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRoadFinderAlgo.h
@@ -113,9 +113,6 @@ private:
   // store all ss not just in roads
   bool m_StoreAllSS; 
 
-  // read FTKHits directly from file
-  bool m_read_FTKhits_directly;
-
   // Plane map pointer, to be set during the initialization
   FTKPlaneMap *m_pmap;
   FTKPlaneMap *m_pmap_unused;
@@ -169,8 +166,12 @@ private:
 
   bool m_AutoDisable; // possibility to avoid internal algorithm execution in particular confitions
 
+  // read FTKHits directly from file
+  bool m_read_FTKhits_directly;
+
   int m_firstEventFTK; // first event to run over
 
+  int m_AMcompressionMode; // compression mode for AM bank
 };
 
 #endif // FTKRoadFinderAlgo_h
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRootFile.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRootFile.h
index c3d42e1c0a9d..8cee39e716dc 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRootFile.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKRootFile.h
@@ -53,9 +53,8 @@ public:
    bool Open(std::string const &fileName);
    // return the directory selected in the last call to Open
    TDirectory *GetDirectory(void) const;
-   //virtual TDirectory *OpenRootFileReadonly(char const *fileName);
-   TDirectory *OpenRootFileReadonly(char const *fileName);
 protected:
+   TDirectory *OpenRootFileReadonly(char const *fileName);
    int m_maxOpenFiles;
    std::vector<std::string> m_fileNames;
    std::map<std::string,TDirectory *> m_openDirectories;
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrack.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrack.h
index a0b232f736b6..1ff9e2acbf2c 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrack.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrack.h
@@ -32,12 +32,12 @@ private:
   float m_origchi2; // In the case of majority recovery, this is the chi2 of 
                     // the full fit. In all other cases m_chi2 == m_origchi2
 
-  int m_invptfw; // curvature value in the output format of the FW
+  float m_invptfw; // curvature value in the output format of the FW
   int m_d0fw; // impact parameter as calculated by the FW
   int m_phifw; // phi value as caculated by the FW
   int m_z0fw; // z0 from the FW
-  int m_cthetafw; //
-  double m_chi2fw; // chisq calculation using the AUX card or SS board firmware-like code
+  int m_cthetafw; // cot(theta) using the AUX card or SS board firmware-like code
+  int m_chi2fw; // chisq calculation using the AUX card or SS board firmware-like code
 
   int m_nmissing; // number of missing coordinates
   unsigned int m_typemask; // set on in bits related to the step recovery were used, ex.: 0 no recovery, 01, rec 1st step, 11, recovery in the 1st and the 2nd stage
@@ -48,6 +48,9 @@ private:
   int m_nplanes; // number of layer planes used
   FTKHit *m_hits; //[m_nplanes] hits associated to the track
 
+  int m_nplanes_ignored; // number of planes to extrapolate the 7L tracks
+  int *m_ssid; // [m_nplanes_ignored] SSIDs associated to the extrapolated AUX tracks
+
   int m_HF_rejected; /* 0 if the track is accepted, >0 if rejected by hit filter
 			if negative, belongs to a HF rejected road
 		     */
@@ -94,12 +97,12 @@ public:
   float getChi2ndof() const { return m_chi2/(m_ncoords-m_nmissing-5); }
   const float& getOrigChi2() const { return m_origchi2; }
   float getOrigChi2ndof() const { return m_origchi2/(m_ncoords-m_nmissing-5); }
-  int getInvPtFW() const { return m_invptfw; }
+  float getInvPtFW() const { return m_invptfw; }
   int getIPFW() const { return m_d0fw; }
   int getPhiFW() const { return m_phifw; }
   int getZ0FW() const { return m_z0fw; }
   int getCTheta() const { return m_cthetafw; }
-  double getChi2FW() const { return m_chi2fw; }
+  int getChi2FW() const { return m_chi2fw; }
   const int&   getNMissing() const { return m_nmissing; }
   const unsigned int& getTypeMask() const { return m_typemask; }
   const unsigned int& getBitmask() const { return m_bitmask; }
@@ -107,6 +110,8 @@ public:
   const int& getNPlanes() const { return m_nplanes; }
   const float& getCoord(int i) const { return m_coord[i]; }
   float *getCoords() { return m_coord; };
+  const int& getNPlanesIgnored() const { return m_nplanes_ignored; }
+  const int& getSSID(int i) const { return m_ssid[i]; }
   const int& getHFRejected() const { return m_HF_rejected; }
   const int& getHWRejected() const { return m_HW_rejected; }
   const int& getHWTrackID() const { return m_HW_track; }
@@ -140,11 +145,12 @@ public:
   void setCotTheta(float v) { m_ctheta = v; }
   void setChi2(float v) { m_chi2 = v; }
   void setOrigChi2(float v) { m_origchi2 = v; }
-  void getInvPtFW(int v) {  m_invptfw = v; }
-  void getIPFW(int v) {  m_d0fw = v; }
-  void getPhiFW(int v) {  m_phifw = v; }
-  void getZ0FW(int v) {  m_z0fw = v; }
-  void getCTheta(int v) {  m_cthetafw = v; }
+  void setInvPtFW(float v) {  m_invptfw = v; }
+  void setIPFW(int v) {  m_d0fw = v; }
+  void setPhiFW(int v,bool ForceRange=true);
+  void setZ0FW(int v) {  m_z0fw = v; }
+  void setCTheta(int v) {  m_cthetafw = v; }
+  void setChi2FW(int v) { m_chi2fw = v; }
   void setChi2FW(double v) { m_chi2fw = v; }
   void setNMissing(int v) { m_nmissing = v; }
   void setTypeMask(unsigned int v) { m_typemask = v; }
@@ -160,10 +166,15 @@ public:
   void setHWTrackID(int v) { m_HW_track = v; }
   void setNPlanes(int);
   void setFTKHit(int i,const FTKHit &hit) const { m_hits[i] = hit; }
+  void setNPlanesIgnored(int);
+  void setSSID(int i, int v) { m_ssid[i] = v; }
 
   // Function used by the HW to compare similar combinations
   unsigned int getNCommonHits(const FTKTrack &, const float*) const;
+  unsigned int getNCommonHitsFirstStage(const FTKTrack &, const float*) const;
+
   int HWChoice(const FTKTrack&,const float*,const unsigned int,int);
+  int HWChoiceFirstStage(const FTKTrack&,const float*,const unsigned int,int);
 
   virtual void Print(Option_t * opts="") const;
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFileOutput.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFileOutput.h
index 8ff980d4528f..b1ab4b702d63 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFileOutput.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFileOutput.h
@@ -58,6 +58,7 @@ class FTKTrackFileOutput : public FTKObjectOutput<FTKTrackStream>, public FTKTra
   { FTKObjectOutput<FTKTrackStream>::setEventNumber(v1,v2); }
 
   void addTrack(int, const FTKTrack&);
+  void addTrack_pre_hw(int, const FTKTrack&);
 
   void addNCombs(int ib, int v)
     { m_data[ib]->addNCombs(v); }
@@ -87,6 +88,8 @@ class FTKTrackFileOutput : public FTKObjectOutput<FTKTrackStream>, public FTKTra
     { m_data[ib]->addNExtrapolatedTracks(v); }
 
   void addTrackI(int, const FTKTrack&);
+  void addTrackI_pre_hw(int, const FTKTrack&);
+
   void addNCombsI(int ib, int v)
     { m_data[ib]->addNCombsI(v); }
   void addNFitsI(int ib, int v)
@@ -110,6 +113,9 @@ class FTKTrackFileOutput : public FTKObjectOutput<FTKTrackStream>, public FTKTra
   void addNFitsHWRejectedMajorityI(int ib, int v)
     { m_data[ib]->addNFitsHWRejectedMajorityI(v); }
 
+  void addTrack_pattern(int, const FTKTrack&);
+  void addTrack_hits(int, const FTKTrack&);
+
 };
 
 #endif // FTKTRACKFILEOUTPUT_H
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFitterAlgo.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFitterAlgo.h
index 16c16f5e804f..e2da04e483f9 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFitterAlgo.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackFitterAlgo.h
@@ -57,12 +57,13 @@ private:
   int m_chi2cut;
   int m_chi2cut_maj;
   int m_chi2cut_vetmaj;
-  int m_chi2dofcut;
+  int m_chi2dofcutAux;
+  int m_chi2dofcutSSB;
 
   bool m_doAuxFW;
  
   int m_HitWarrior;
-  int m_HitWarrior_first;
+  bool m_AuxDoctor;
   int m_KeepRejected; 
   int m_FitRemoved;
   int m_DoMajority;
@@ -87,6 +88,7 @@ private:
   float m_SSF_TR_max_eta;
 
   bool m_save_1stStageTrks;
+  bool m_save_StepByStepTrks;
 
   //output
   bool m_doTrackFile;
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackOutput.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackOutput.h
index 3658552e51aa..1696b15ccc98 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackOutput.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackOutput.h
@@ -41,6 +41,7 @@ public:
 
 
   virtual void addTrack(int, const FTKTrack&) = 0;
+  virtual void addTrack_pre_hw(int, const FTKTrack&) = 0;
 
   virtual void addNCombs(int ib, int v) = 0;
   virtual void addNFits(int ib, int v) = 0;
@@ -57,6 +58,8 @@ public:
   virtual void addNExtrapolatedTracks(int ib, int v) = 0;
 
   virtual void addTrackI(int, const FTKTrack&) = 0;
+  virtual void addTrackI_pre_hw(int, const FTKTrack&) = 0;
+  
   virtual void addNCombsI(int ib, int v) = 0;
   virtual void addNFitsI(int ib, int v) = 0;
   virtual void addNFitsMajorityI(int ib, int v) = 0;
@@ -69,6 +72,9 @@ public:
   virtual void addNFitsBadMajorityI(int ib, int v) = 0;
   virtual void addNFitsHWRejectedMajorityI(int ib, int v) = 0;
 
+  virtual void addTrack_pattern(int, const FTKTrack&) = 0;
+  virtual void addTrack_hits(int, const FTKTrack&) = 0;
+
 };
 
 #endif // FTKTRACKOUTPUT_H
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackStream.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackStream.h
index fe9f5bd930a9..4faf7050ccde 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackStream.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTKTrackStream.h
@@ -18,7 +18,9 @@ private:
   unsigned long m_event_number; // event number
 
   int m_ntracks; // number of stored tracks
+  int m_ntracks_pre_hw; // number of stored tracks before Hit Warrior
   TClonesArray *m_tracks; //-> list of stored tracks
+  TClonesArray *m_tracks_pre_hw; //-> list of stored tracks before Hit Warrior
 
   int m_ncombs; // number of combinations
   int m_nfits; // number of fitted combinations
@@ -35,9 +37,10 @@ private:
      to m_nfits-m_nfits_bad-m_nfits_rej */
   
   int m_ntracksI; // number of stored tracks in the intermediate step
+  int m_ntracksI_pre_hw; // number of stored tracks in the intermediate step before Hit Warrior
 
   TClonesArray *m_tracksI; //-> list of stored tracks in the intermedieate step
-
+  TClonesArray *m_tracksI_pre_hw; //-> list of stored tracks in the intermedieate step before Hit Warrior
 
   // duplicate the counters for the 2nd stage
   int m_ncombsI;
@@ -53,6 +56,10 @@ private:
   int m_nfits_rejmajI;
   int m_nconn;
   int m_nextrapolatedTracks;
+  int m_ntracks_pattern; // number of stored tracks with patterns
+  int m_ntracks_hits; // number of stored tracks that pass hit requirements
+  TClonesArray *m_tracks_pattern; //-> list of stored tracks with patterns
+  TClonesArray *m_tracks_hits; //-> list of stored tracks that pass hit requirements
 
   std::map< std::pair<int,int>, int > m_trackIdMap; //! Not saved on disk.  
   // Used to optimize the findTrack function. 
@@ -72,10 +79,26 @@ public:
   int getNTracks() const { return m_ntracks; }
   void buildTrackMap(); 
 
+  void addTrack_pre_hw(const FTKTrack&);
+  FTKTrack* getTrack_pre_hw(int) const;
+  int getNTracks_pre_hw() const { return m_ntracks_pre_hw; }
+
   void addTrackI(const FTKTrack&);
   FTKTrack* getTrackI(int) const;
   int getNTracksI() const { return m_ntracksI; }
 
+  void addTrackI_pre_hw(const FTKTrack&);
+  FTKTrack* getTrackI_pre_hw(int) const;
+  int getNTracksI_pre_hw() const { return m_ntracksI_pre_hw; }
+
+  void addTrack_pattern(const FTKTrack&);
+  FTKTrack* getTrack_pattern(int) const;
+  int getNTracks_pattern() const { return m_ntracks_pattern; }
+
+  void addTrack_hits(const FTKTrack&);
+  FTKTrack* getTrack_hits(int) const;
+  int getNTracks_hits() const { return m_ntracks_hits; }
+
   int getNConn() const {return m_nconn;}
   int getNExtrapolatedTracks() const {return m_nextrapolatedTracks;}
 
@@ -134,7 +157,7 @@ public:
 
   int Print(int level=0,std::ostream &out=std::cout);
 
-  ClassDef(FTKTrackStream,12)
+  ClassDef(FTKTrackStream,13)
 };
 
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedAMBank.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedAMBank.h
index bab734ab8cf5..eb78487448dc 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedAMBank.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedAMBank.h
@@ -10,6 +10,8 @@
 #include "TrigFTKSim/FTKPattern.h"
 #include "TrigFTKSim/FTKRoad.h"
 #include "TrigFTKSim/FTK_AMsimulation_base.h"
+#include "TrigFTKSim/FTK_CompressedSectorPatternList.h"
+#include "TrigFTKSim/FTK_HitMask.h"
 #include <inttypes.h>
 #include <vector>
 #include <map>
@@ -33,6 +35,8 @@ class FTKHitPatternCompare;
 class FTKPatternOneSector;
 class FTKPatternBySectorReader;
 
+#define ROAD_CAND_AS_VECTOR
+
 //#include <boost/container/map.hpp>
 //#include <boost/container/vector.hpp>
 //#include <boost/container/list.hpp>
@@ -43,56 +47,6 @@ class FTKPatternBySectorReader;
 #define VECTOR std::vector
 #define LIST std::list
 
-#define OPTIMIZED_VECTORMAP
-
-#ifdef OPTIMIZED_VECTORMAP
-// this map has a parallel linear stucture for fast loops
-//   using the type "const_ptr" rather than "const_iterator"
-template<class T> class VECTORMAP : public MAP<int,T> {
- public:
-   VECTORMAP() : m_data(0),m_size(0) { }
-   virtual ~VECTORMAP() { if(m_data) delete [] m_data; }
-   class const_ptr {
-   public:
-      inline const_ptr(typename std::pair<const int,T> const **p=0) : m_ptr(p) {
-      }
-      inline typename std::pair<const int,T> const &operator*(void) {
-         return **m_ptr;
-      }
-      inline bool operator!=(const_ptr const &cp) { return m_ptr!=cp.m_ptr; }
-      inline const_ptr &operator++(void) { ++m_ptr; return *this; }
-   protected:
-      typename std::pair<const int,T> const **m_ptr;
-   };
-   int getMemoryEstimate(void) const {
-      // size of the class
-      // data and four pointers (data,prev,next,child) per node
-      // plus array of pointers for fast access using "const_ptr"
-      return
-         ((uint8_t const *)(this+1)-(uint8_t const *)this)+
-         (sizeof(typename std::pair<int, T>)+4*sizeof(void *))
-         *MAP<int,T>::size()
-         +sizeof(void *)*m_size;
-   }
-   inline const_ptr beginPtr(void) const { return m_data; }
-   inline const_ptr endPtr(void) const { return m_data+m_size; }
-   inline void pack() {
-      if(m_data) { delete [] m_data; m_data=0; }
-      m_size=MAP<int,T>::size();
-      if(m_size) {
-         m_data=new typename std::pair<const int,T> const * [m_size];
-         unsigned k=0;
-         for(typename MAP<int,T>::const_iterator i=MAP<int,T>::begin();
-             i!=MAP<int,T>::end();i++) {
-            m_data[k++]=&(*i);
-         }
-      }
-   }
- protected:
-   typename std::pair<const int,T> const **m_data;
-   unsigned m_size;
-};
-#else
 template<class T> class VECTORMAP : public MAP<int,T> {
 public:
    typedef typename MAP<int,T>::const_iterator const_ptr;
@@ -108,7 +62,6 @@ public:
           +4*sizeof(void *))*MAP<int,T>::size();
    }
 };
-#endif
 
 class FTK_CompressedAMBank : public FTKLogging , public FTK_AMsimulation_base {
 public:
@@ -120,6 +73,21 @@ public:
                         int hwmodeid_TSP=-1,int hwmodeid_DC=-1,
                         char const *name="FTK_CompressedAMBank");
 
+   // set compression scheme
+  //
+  // compression scheme
+  enum COMPRESSION {
+     COMPRESSION_SKIP=-1,   // skip "finalize step"
+     COMPRESSION_DEFAULT=0, // use default compression scheme
+
+     COMPRESSION_U7=FTK_CompressedPatternList::ENCODING_U7,
+     COMPRESSION_U32=FTK_CompressedPatternList::ENCODING_U32,
+     COMPRESSION_DELTA=FTK_CompressedPatternList::ENCODING_DELTA,
+     COMPRESSION_BIT4=FTK_CompressedPatternList::ENCODING_BIT4
+  };
+   void setCompressionScheme(int scheme);
+   inline int getCompressionScheme(void) const { return m_compressionScheme; };
+
    // set parameters for TSP import
    void setNDCmax(int ndc);
    void setNDCmaxPlane(size_t plane,int ndc);
@@ -152,7 +120,7 @@ public:
    // write root file (reasonaby fast)
    int writeCCachedBankFile(char const *cachedBankFile,int flatFormat=0) const;
    int writeCCachedBankFile(TDirectory *out) const;
-  
+
    // full comparison of two pattern banks
    int compare(FTK_CompressedAMBank const *bank) const;
 
@@ -189,12 +157,12 @@ public:
    // argument is SSID w/o dc bits
    // returns vector with dc-bit as index, contains TSP-SSID
    // (note, the dc-bits possibly are gray-coded)
-   std::vector<int> const &getTSPssidVector(int layer,int sector,int dcSSID);
-   inline int getTSPssid(int layer,int sector,int dcSSID,int tspXY) {
-      return getTSPssidVector(layer,sector,dcSSID)[tspXY];
+   std::vector<int> const &getTSPssidVector(int layer,int dcSSID);
+   inline int getTSPssid(int layer,int dcSSID,int tspXY) {
+      return getTSPssidVector(layer,dcSSID)[tspXY];
    }
    // returns pair(SSID w/o dc bits , dc bits)
-   std::pair<int,int> const &getDCssid(int layer,int sector,int tspSSID);
+   std::pair<int,int> const &getDCssid(int layer,int tspSSID);
    int getDCssidConst(int layer,int tspSSID) const;
 
    // read root file (sector-ordered), one subregion
@@ -221,18 +189,16 @@ public:
 
    bool isReservedPatternId(int patternID) const;
 
-   int readBANKjson(char const *jsonFile);
-   int writeBANKjson(char const *jsonFile) const;
-
    void printStrips(int plane=-1) const;
 
-protected:
    // read root file (pcache)
    int readPCachedBank(TDirectory *pcache,int nsub=0);
 
    // read root file (Compressed cache)
    int readCCachedBank(TDirectory *ccache);
 
+protected:
+
    // convert sector-ordered DC bank (in memory) to TSP-bank
    void importDCpatterns
       (int nLayer,int offsetSSID,int32_t *ssidData,
@@ -253,42 +219,57 @@ protected:
 
    VECTOR<MAP<int,int> > m_badModules;
 
-   // hold pattern data for a given layer,SSID,sector (all patterns)
    //
-   // loop over packed pattern data
+   // holds pattern data for a given layer (all SSIDs and all sectors)
+   //    the index is the SSID number (in TSP space)
+   typedef VECTORMAP<FTK_CompressedSectorPatternList> PatternBySectorSSidMap_t;
+
    //
-   // packed pattern data - store delta to preceeding pattern
-   //   0x00-0x7f : delta=1..128
-   //   0x8x : store bit  7..10 if delta-1>0x0000007f
-   //   0x9x : store bit 11..14 if delta-1>0x000007ff
-   //    ...
-   //   0xDx : store bit 27..30 if delta-1>0x07ffffff
-   //   0xE1 : store bit 31     if delta-1>0x7fffffff
-   //   0xE4..0xE7 : store length (1..4 byte, big-endian)
-   //   0xE8..0xEB : store nPatterns (1..4 byte, big-endian)
-   //   0xEC..0xEF : store firstPattern address relative to sector start
-   //                  (1..4 byte, big-endian)
-   //   0xFx : encode repeated occurance of delta=1 (repeat=2..17)
-   template<class A>
-      inline void patternLoop(A &a,uint8_t const * __restrict ptr,
-                              uint32_t firstPattern,int nPattern) const;
-   struct SectorData {
+   // store SSID and ternary bits by pattern ID for one layer
+   struct SSIDternaryByPattern {
+      //
+      // dcSSID IDs by sector (for unpacking pattern data)
+      //    m_dcSSIDtable[sector][i]  is an SSID (in dc-space)
+      VECTOR<VECTOR<int> > m_dcSSIDbySectorIndex;
+      //
+      // the data
+      std::vector<uint8_t> m_pattern8DataPacked;
+      std::vector<uint16_t> m_pattern16DataPacked;
       //
-      // first pattern ID
-      uint32_t m_FirstPattern;
+      // offset for unpacking ternary bits
+      uint32_t m_offsetTernary;
+      //
+      // method to extract packed data
+      inline uint16_t getPackedData(uint32_t patternID) const {
+         uint16_t data;
+         if(patternID<m_pattern8DataPacked.size())
+            data=m_pattern8DataPacked[patternID];
+         else data=m_pattern16DataPacked[patternID];
+         return data;
+      }
       //
-      // number of patterns (unpacked)
-      uint32_t m_NPattern;
-      uint32_t m_offset;
-      uint32_t m_length;
+      // method to unpack SSID
+      inline int getSSID(uint32_t sector,uint32_t patternID) const {
+         uint32_t data=getPackedData(patternID);
+         uint32_t indexSSID=(data-1)/m_offsetTernary;
+         return m_dcSSIDbySectorIndex[sector][indexSSID];
+      }
+      //
+      // method to unpack ternary bits
+      //   return.first : DC bits
+      //   return .second : HB bits
+      inline std::pair<uint16_t,uint16_t> getDCHB(int patternID)
+         const {
+         std::pair<uint16_t,uint16_t> r(std::make_pair(0,0));
+         uint32_t data=(getPackedData(patternID)-1)%m_offsetTernary;
+         for(int bits3=m_offsetTernary/3;bits3;bits3/=3) {
+            int t=(data/bits3)%3;
+            r.second = (r.second<<1)|(t &1);
+            r.first = (r.first<<1)|(t>>1);
+         }
+         return r;
+      }
    };
-
-   //
-   // holds pattern data for a given layer (all SSIDs and all sectors)
-   //    the index is the SSID number (in TSP space)
-   typedef VECTORMAP<SectorData> PatternBySector_t;
-   typedef VECTORMAP<PatternBySector_t> PatternBySectorSSidMap_t;
-   //    the index is the sector number
    //
    // holds patterndata and auxillary data for a given layer
    struct LayerData {
@@ -298,13 +279,28 @@ protected:
       //          list of patterns for this SSID,sector combination
       PatternBySectorSSidMap_t m_SSidData;
       //
-      // dcSSID IDs by sector (for unpacking pattern data)
-      //    m_dcSSIDtable[sector][i]  is an SSID (in dc-space)
-      VECTOR<VECTOR<int> > m_dcSSIDbySectorIndex;
-      //
-      // this holds the byte-compressed pattern delta data by sector
-      VECTOR<VECTOR<uint8_t> > m_CompressedDeltaBySector;
+      // this holds the Pattern data, ordered by patternID 
+      //  each word is packed as:
+      //     DC*m_offsetTernary+TERNARY
+      // TERNARY is packed using {0,1,X} <-> {0,1,2}
+      struct SSIDternaryByPattern m_SSIDternaryByPattern;
   };
+   class Range {
+   public:
+      inline Range(void) : m_head(0),m_tail(0) { }
+      inline int First(void) const {return m_head; }
+      inline int Last(void) const {return m_tail-1; }
+      inline int Size(void) const { return m_tail-m_head; }
+      inline void SetRange(int first,int last) {
+         m_head=first; m_tail=last+1; }
+      inline void UpdateRange(int first,int last) {
+         if(Size()<=0) SetRange(first,last);
+         else {
+            if(first<m_head) m_head=first;
+            if(last>=m_tail) m_tail=last+1; } }
+   protected:
+      int m_head,m_tail;
+   };
    //
   // hold a full pattern bank
   struct PatternBank {
@@ -315,39 +311,43 @@ protected:
      //       returns the coresponding struct SectorData
      VECTOR<LayerData> m_PatternByLayer;
      //
-     // this holds the Pattern data, ordered by patternID (bit-packed)
-     //   the bit number is given by iPattern*m_PatternBitsTotal
-     VECTOR<std::vector<uint8_t> > m_pattern8Data;
-     VECTOR<std::vector<uint16_t> > m_pattern16Data;
      //
      // this holds auxillary information (if available)
      //  number of TSP patterns per pattern
      //  integrated coverage per pattern
      VECTOR<uint32_t> m_numTSP,m_coverage;
+     //
+     // for each sector, give the pattern range
+     VECTOR<Range> m_PatternRangeBySector;
   };
   void erase();
   //
   // holds all pattern data
   PatternBank m_bank;
-  MAP<int,std::pair<int,int> > m_SectorFirstLastPattern;
+  MAP<int,bool> m_tooFew;
+
+  //
+  // types to hold hit-mask for a pattern
   //
   // hold wildcards (layer mask) per sector
-  typedef uint8_t HitPattern_t;
-  VECTOR<HitPattern_t> m_SectorWC;
+  VECTOR<FTK_HitMask> m_SectorWC;
   //
   // TSP-SSIDs 
   std::vector<std::list<int> > m_tspSSID;
   //
   // used sectors
-  VECTOR<HitPattern_t> m_sectorUsage;
+  VECTOR<FTK_HitMask> m_sectorUsage;
   //
   // hit patterns 
-  VECTOR<HitPattern_t> m_hitPatterns;
+  FTK_HitMaskVector m_hitMask;
   //
   // road candidates
-  static int const MAX_NROAD;
-  unsigned m_nRoadCand;
-  VECTOR<std::pair<uint32_t,uint32_t> > m_roadCand;
+#ifdef ROAD_CAND_AS_VECTOR
+  static int const MAX_ROADCAND;
+  std::vector<std::pair<uint32_t,uint32_t> > m_roadCand;
+#else
+  VECTORMAP<uint32_t> m_roadCandMap;
+#endif
   //
   // minimum number of hits
   uint8_t m_nhWCmin;
@@ -365,9 +365,9 @@ protected:
   // these methods are used to populate tables to translate
   //   tspSSID to dcSSID and back
   //   (this should be moved to another class?)
-  int getTSPssidSlow(int layer,int sector,int ssid,int tspXY);
-  int getDCssidSlow(int layer,int sector,int tspSSID,int *moduleID);
-  void insertSSID(int layer,int sector,int tspSSID,int dcSSID);
+  int getTSPssidSlow(int layer,int ssid,int tspXY);
+  int getDCssidSlow(int layer,int tspSSID,int *moduleID);
+  void insertSSID(int layer,int tspSSID,int dcSSID);
   void invalidateSSIDtables(void);
 
   //
@@ -378,11 +378,9 @@ protected:
   VECTOR<MAP<int,std::pair<int,int> > > m_TSPtoDC;
   //
   // lookup-tables to convert compressed DC bits to subSSmask,DC,HB
-  //    m_subSSmask[layer][dcHBbits]  returns the subSSmask for this layer
   //    m_dcMaskLookup[layer][dcHBbits]  returns the DC bits for this layer
   //    m_hbMaskLookup[layer][dcHBbits]  returns the HB bits for this layer
   // here, dcHBbits is extracted from bits inside m_Bank.m_PatternBitData[]
-  VECTOR<VECTOR<int> > m_subSSmask;
   VECTOR<VECTOR<int> > m_dcMaskLookup;
   VECTOR<VECTOR<int> > m_hbMaskLookup;
   // lookup-tables to get encoded (DC,HB) bits given the subindex of TSP wrt DC
@@ -429,10 +427,7 @@ protected:
   // identifier for wildcard SS
   static int const s_WILDCARDid;
   static int const s_INVALIDid;
-  //
-  // for generating HUF table
-  void SplitlistHUF(uint64_t code,int *i2char,int *integral,int i0,int i1,
-                    VECTOR<int> &huftable,VECTOR<uint64_t> &hufcode) const;
+  int m_compressionScheme;
 };
 
 #endif
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedPatternList.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedPatternList.h
new file mode 100644
index 000000000000..76f6c55ca07d
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedPatternList.h
@@ -0,0 +1,396 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __H_FTK_COMPRESSEDPATTERNLIST
+#define __H_FTK_COMPRESSEDPATTERNLIST
+
+#include <inttypes.h>
+#include <set>
+#include <vector>
+#include <TObject.h>
+
+class FTK_CompressedPatternList {
+ public:
+   // crompression schemes
+   enum ENCODING_SCHEME {
+      ENCODING_MIN=1,
+      ENCODING_U32=1,
+      ENCODING_U7=2,
+      ENCODING_DELTA=3,
+      ENCODING_BIT4=4,
+      ENCODING_DELTA2=5,
+      ENCODING_MAX=5
+   };
+
+   // create
+   FTK_CompressedPatternList(uint32_t firstPattern,uint32_t nPattern,
+                             uint32_t nData,uint32_t encoding,uint8_t *data)
+      : m_NPattern(nPattern) {
+      setData(firstPattern,encoding,data,nData);
+   }
+   //
+   inline void setData(uint32_t firstPattern,uint32_t encoding,
+                       std::vector<uint8_t> &data) {
+      setData(firstPattern,encoding,data.data(),data.size()); }
+   void setData(uint32_t firstPattern,uint32_t encoding,
+                uint8_t const *dataPtr,uint32_t nData);
+   inline void setDataPointer(uint8_t const *data) { m_data=data; }
+   // pattern range
+   std::pair<uint32_t,uint32_t> getMinMaxPattern(void) const;
+   // number of patterns
+   inline uint32_t getNPattern(void) const { return m_NPattern; }
+   // encoding scheme
+   inline uint32_t getEncoding(void) const { return m_encoding; }
+   // select encoding scheme
+   uint32_t selectEncoding(uint32_t defaultMode) const;
+   // change to different encoding scheme
+   // returns: new data size if successful
+   //          -1 if new encoding is worse than before
+   void encode(uint32_t encoding,uint32_t *firstPattern,
+               std::vector<uint8_t> &data) const;
+   // export data (for TTree)
+   void exportData(Int_t *firstPattern,Int_t *nPattern,Int_t *encoding,
+                   std::vector<Int_t> &deltaData) const;
+   // unpack and loop over all patterns
+   template<class LOOP> inline void patternLoop(LOOP &loop) const {
+      // start pattern ID
+      loop.init(m_FirstPattern);
+      uint8_t const * __restrict ptr=m_data;
+      if(m_encoding == ENCODING_U7) {
+         loop.process();
+         for(int nPattern=m_loopHelper;nPattern>0;nPattern--) {
+            uint32_t delta;
+            delta=nextByte(ptr);
+            loop.update(delta+1);
+            loop.process();
+         }
+         for(int nPattern=m_NPattern-1-m_loopHelper;nPattern>0;nPattern--) {
+            uint32_t delta;
+            delta=nextByte(ptr);
+            if(delta & 0x80) {
+               uint32_t up=0;
+               do {
+                  up=(up|(delta&0x7f))<<7;
+                  delta=nextByte(ptr);
+               } while(delta & 0x80);
+               delta |= up;
+            }
+            loop.update(delta+1);
+            loop.process();
+         }
+      } else if(m_encoding == ENCODING_DELTA) {
+         // delta scheme: first pattern is processed directly
+         loop.process();
+         //for(int nPattern=m_NPattern-1;nPattern>0;nPattern--) {
+         for(int iLoop=m_loopHelper;iLoop>0;iLoop--) {
+            uint32_t delta=nextByte(ptr)+1;
+            if(delta>0x80) {
+               if(delta>0xf0) {
+                  delta -=0xef; // original 0xf0-> f1 ->2
+                  //nPattern -= delta-1;
+                  do {
+                      loop.update(1);
+                      loop.process();
+                      delta--;
+                  } while(delta>1);
+               } else {
+                  uint32_t d=delta-1;
+                  delta=1;
+                  do {
+                     // pattern with more than 7 bits
+                     //  add non-zero high bits in groups of 4 bits
+                     int shift=((d>>2)&0x3c)-25;
+                     delta += (d&0xf)<<shift;
+                     d=nextByte(ptr);
+                  } while(d & 0x80);
+                  delta += d;
+               }
+            }
+            loop.update(delta);
+            loop.process();
+         }
+      } else if(m_encoding == ENCODING_BIT4) {
+         // BIT4 scheme
+         for(int nData=m_nData;nData>0;nData--) {
+            uint8_t bit4=nextByte(ptr);
+            if(bit4<0x80) {
+               // 00..0x7f  : skip 4*N+4 patterns
+               loop.update((bit4<<2)+4);
+            } else if(bit4<=0xf0) {
+               // 0x80..0xf0  : set 4*(N-0x7f) patterns
+               for(bit4=bit4-0x7f ; bit4;bit4--) {
+                  loop.process(); loop.update(1);
+                  loop.process(); loop.update(1);
+                  loop.process(); loop.update(1);
+                  loop.process(); loop.update(1);
+               }
+            } else {
+               // 0xf1..0xff  : set bits
+               if(bit4&0x1) loop.process();
+               loop.update(1);
+               if(bit4&0x2) loop.process();
+               loop.update(1);
+               if(bit4&0x4) loop.process();
+               loop.update(1);
+               if(bit4&0x8) loop.process();
+               loop.update(1);
+            }
+         }
+      } else if(m_encoding == ENCODING_DELTA2) {
+         // DELTA2 scheme, similar DELTA but make better use of
+         //  all characters
+         // delta scheme: first pattern is processed directly
+         loop.process();
+         //for(int nPattern=m_NPattern-1;nPattern>0;nPattern--) {
+         for(int iLoop=m_loopHelper;iLoop>0;iLoop--) {
+            uint32_t delta;
+            delta=nextByte(ptr);
+            if(delta & 0x80) {
+               if(delta<0xc0) {
+                  uint32_t up=0;
+                  do {
+                     up=(up|(delta&0x7f))<<6;
+                     delta=nextByte(ptr);
+                  } while(delta & 0x80);
+                  delta |= (up<<1);
+               } else {
+                  delta-=0xbf;
+                  do {
+                      loop.update(1);
+                      loop.process();
+                      --delta;
+                  } while(delta>0);
+               }
+            }
+            loop.update(delta+1);
+            loop.process();
+         }
+      } else if(m_encoding == ENCODING_U32) {
+         loop.process();
+         for(int nPattern=m_NPattern-1;nPattern>0;nPattern--) {
+            uint32_t delta;
+            delta=nextByte(ptr);
+            delta |= ((uint32_t)nextByte(ptr))<<8;
+            delta |= ((uint32_t)nextByte(ptr))<<16;
+            delta |= ((uint32_t)nextByte(ptr))<<24;
+            loop.update(delta);
+            loop.process();
+         }
+      }
+   }
+ protected:
+   inline uint8_t nextByte(uint8_t const * __restrict &ptr) const {
+      return *(ptr++);
+   }
+   //
+   // first pattern ID
+   uint32_t m_FirstPattern;
+   //
+   // number of patterns (unpacked)
+   uint32_t m_NPattern;
+   //
+   // number of bytes
+   uint32_t m_nData;
+   //
+   // compression scheme
+   uint32_t m_encoding;
+   //
+   // helper to speed up loops
+   uint32_t m_loopHelper;
+   //
+   // pointer to data
+   uint8_t const * __restrict m_data;
+};
+
+class FTK_CompressedPatternListLoopWithCounter_base {
+ public:
+   inline virtual void init(uint32_t basePattern) { m_pattern=basePattern; }
+   inline void update(uint32_t delta) { m_pattern += delta; }
+   inline uint32_t getPattern(void) const { return m_pattern; }
+ private:
+   uint32_t m_pattern;
+};
+
+class FTK_CompressedPatternListEncoder_base
+: public FTK_CompressedPatternListLoopWithCounter_base {
+ public:
+   virtual ~FTK_CompressedPatternListEncoder_base(void) { }
+   // empty encoder
+   // user may implement storeFirst()
+   // user has to implement storeNext()
+   FTK_CompressedPatternListEncoder_base(std::vector<uint8_t> &data)
+      : m_data(data),m_firstPattern(0),m_nPattern(0) {
+      m_data.resize(0); }
+   virtual void storeFirst(void) { }
+   virtual void storeNext(void) =0;
+   void process(void) {
+      if(m_nPattern==0) {
+         m_firstPattern=getPattern();
+         storeFirst();
+      } else {
+         storeNext();
+      }
+      m_nPattern++;
+      m_previousPattern=getPattern();
+   }
+   uint32_t getFirstPattern(void) const { return m_firstPattern; }
+ protected:
+   std::vector<uint8_t> &m_data;
+   uint32_t m_firstPattern;
+   uint32_t m_nPattern;
+   uint32_t m_previousPattern;
+};
+
+class FTK_CompressedPatternListBIT4Encoder
+   : public FTK_CompressedPatternListEncoder_base {
+public:
+   FTK_CompressedPatternListBIT4Encoder(std::vector<uint8_t> &data)
+      : FTK_CompressedPatternListEncoder_base(data) { }
+   virtual void storeFirst(void) {
+      m_data.push_back((1<<(m_firstPattern & 0x03))|0xf0);
+      m_firstPattern &= 0xfffffffc;
+   }
+   virtual void storeNext(void) {
+      uint32_t bit=getPattern()-(m_previousPattern & 0xfffffffc);
+      if(bit>3) {
+         // insert zeros, then start new byte
+         uint32_t nZero4=(bit>>2)-1;
+         while(nZero4>0) {
+            if(nZero4>0x80) {
+               m_data.push_back(0x7f);
+               nZero4 -=0x80;
+            } else {
+               m_data.push_back(nZero4-1);
+               nZero4=0;
+            }
+         }
+         m_data.push_back((1<<(bit &3))|0xf0);
+      } else {
+         // add bit to previous
+         uint32_t n1=m_data.size()-1;
+         uint8_t data=m_data[n1]|(1<<bit);
+         m_data[n1]=data;
+         if(data==0xff) {
+            // possibly merge with previous
+            if(n1>0) {
+               uint8_t &prev=m_data[n1-1];
+               if((prev>=0x80)&&(prev<0xf0)) {
+                  prev++;
+                  m_data.resize(n1);
+               }
+            }
+         }
+      }
+   }
+};
+
+class FTK_CompressedPatternListU32Encoder
+   : public FTK_CompressedPatternListEncoder_base {
+public:
+   FTK_CompressedPatternListU32Encoder(std::vector<uint8_t> &data)
+      : FTK_CompressedPatternListEncoder_base(data) { }
+   virtual void storeNext(void) {
+      uint32_t delta=getPattern()-m_previousPattern;
+      m_data.push_back(delta);
+      m_data.push_back(delta>>8);
+      m_data.push_back(delta>>16);
+      m_data.push_back(delta>>24);
+   }
+};
+
+class FTK_CompressedPatternListU7Encoder
+   : public FTK_CompressedPatternListEncoder_base {
+public:
+   FTK_CompressedPatternListU7Encoder(std::vector<uint8_t> &data)
+      : FTK_CompressedPatternListEncoder_base(data) { }
+   virtual void storeNext(void) {
+      uint32_t delta=getPattern()-m_previousPattern-1;
+      if(delta & 0xf0000000) m_data.push_back((delta>>28)|0x80);
+      if(delta & 0xffe00000) m_data.push_back((delta>>21)|0x80);
+      if(delta & 0xffffc000) m_data.push_back((delta>>14)|0x80);
+      if(delta & 0xffffff80) m_data.push_back((delta>>7)|0x80);
+      m_data.push_back(delta & 0x7f);
+   }
+};
+
+class FTK_CompressedPatternListDeltaEncoder
+   : public FTK_CompressedPatternListEncoder_base {
+public:
+   FTK_CompressedPatternListDeltaEncoder(std::vector<uint8_t> &data)
+      : FTK_CompressedPatternListEncoder_base(data) { }
+   virtual void storeNext(void) {
+      uint32_t delta=getPattern()-m_previousPattern-1;
+      uint32_t mask4=0x780;
+      int shift=7;
+      // check whether some bits >=7 are nonzero
+      //  -> need extra bytes to store this delta
+      for(uint32_t mask=0xffffff80;mask;mask<<=4) {
+         if((delta & mask)==0) break;
+         uint32_t bits=delta & mask4;
+         if(bits) m_data.push_back( (bits>>shift)|((shift+25)<<2) );
+         mask4 <<=4;
+         shift+=4;
+      }
+      if(!delta) {
+         uint8_t prev=0xff;
+         uint8_t pprev=0;
+         uint32_t n1=m_data.size()-1;
+         if(m_data.size()>0) {
+            prev=m_data[n1];
+            if(n1>0) pprev=m_data[n1-1];
+         }
+         if((prev==0x00)&&(pprev<0x80)) {
+            // repeat 2x
+            m_data[n1]=0xf0;
+         } else if((prev>=0xF0)&&(prev<0xFF)) {
+            // repeat 3+x times
+            m_data[n1]=prev+1;
+         } else {
+            // normal byte
+            m_data.push_back(0);
+         }
+      } else {
+         m_data.push_back(delta & 0x7f);
+      }
+   }
+};
+
+class FTK_CompressedPatternListDelta2Encoder
+   : public FTK_CompressedPatternListEncoder_base {
+public:
+   FTK_CompressedPatternListDelta2Encoder(std::vector<uint8_t> &data)
+      : FTK_CompressedPatternListEncoder_base(data) { }
+   virtual void storeNext(void) {
+      uint32_t delta=getPattern()-m_previousPattern-1;
+      if(delta==0) {
+         int n1=m_data.size()-1;
+         uint8_t pprev=1;
+         uint8_t prev=1;
+         if(n1>=0) {
+            prev=m_data[n1];
+            if(n1>0) pprev=m_data[n1-1];
+         }
+         if((prev==0)&&(pprev<0x80)) {
+            // merge zero -> c0
+            m_data[n1]=0xc0;
+         } else if((prev>=0xc0)&&(prev<0xff)) {
+            m_data[n1]++; // c0->c1 ... fe->ff
+         } else {
+            // no packing for this byte
+            m_data.push_back(0);
+         }
+      } else {
+         if(delta & 0x80000000) m_data.push_back(((delta>>31)&0x3f)|0x80);
+         if(delta & 0xfe000000) m_data.push_back(((delta>>25)&0x3f)|0x80);
+         if(delta & 0xfff80000) m_data.push_back(((delta>>19)&0x3f)|0x80);
+         if(delta & 0xffffe000) m_data.push_back(((delta>>13)&0x3f)|0x80);
+         if(delta & 0xffffff80) m_data.push_back(((delta>>7)&0x3f)|0x80);
+         m_data.push_back(delta & 0x7f);
+      }
+   }
+};
+
+
+#endif
+
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedSectorPatternList.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedSectorPatternList.h
new file mode 100644
index 000000000000..01db0093b417
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_CompressedSectorPatternList.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __H_FTK_COMPRESSEDSECTORPATTERNLIST
+#define __H_FTK_COMPRESSEDSECTORPATTERNLIST
+
+#include "TrigFTKSim/FTK_CompressedPatternList.h"
+#include <map>
+#include <vector>
+
+class FTK_CompressedSectorPatternList
+: public std::map<uint32_t,FTK_CompressedPatternList> {
+ public:
+   FTK_CompressedSectorPatternList(void);
+   ~FTK_CompressedSectorPatternList();
+   // import patterns for one sector
+   void importPatternSet(uint32_t sector,std::set<uint32_t> const &patterns,
+                         int encoding);
+   // finalize patterns after importing them
+   void finalize(int compressionType);
+   // query total number of patterns
+   uint32_t getNPattern(void) const;
+   // query maximum sector number
+   inline uint32_t maxSector(void) const { return (*rbegin()).first; }
+   // get memory estimate
+   uint32_t getMemoryEstimate(void) const;
+
+   // loop over all sectors and patterns
+   template<class LOOP> inline void patternLoop(LOOP &loop) const {
+      for( std::map<uint32_t,FTK_CompressedPatternList>::const_iterator
+              iSector=begin();iSector!=end();iSector++) {
+         if(loop.setSector((*iSector).first)) {
+            (*iSector).second.patternLoop(loop);
+         }
+      }
+   }
+   
+   // import data from TTree
+   void importData(uint32_t sector,uint32_t firstPattern,
+                   uint32_t nPattern,uint32_t encoding,uint32_t nData,
+                        Int_t const *intData);
+
+ protected:
+   size_t m_total;
+   uint8_t *m_compressedData;
+   std::map<uint32_t,std::vector<uint8_t> > *m_tempBuffer;
+};
+
+#endif
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_HitMask.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_HitMask.h
new file mode 100644
index 000000000000..c80498cc4686
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_HitMask.h
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __H_FTK_HITMASKVECTOR
+#define __H_FTK_HITMASKVECTOR
+
+#include <inttypes.h>
+#include <vector>
+#include <utility>
+#include <cstring>
+#include <iostream>
+#include <iomanip>
+
+typedef uint8_t FTK_HitMask;
+
+class FTK_HitMaskIterator {
+ public:
+   FTK_HitMaskIterator(FTK_HitMask *ptr=0) : m_ptr(ptr) { }
+   void setLayer(uint8_t layer) { m_mask=1<<layer; }
+   inline void update4(int delta4) { m_ptr += delta4<<2; }
+   inline void update(int delta) { m_ptr += delta; }
+   inline uint8_t getChange(FTK_HitMask xorMask) {
+      return (((uint8_t)(xorMask-1))>>(8*sizeof(FTK_HitMask)-1))-1;
+   }
+   inline uint8_t process(void) {
+      FTK_HitMask m0=*m_ptr;
+      FTK_HitMask m1=m0|m_mask;
+      *m_ptr=m1;
+      return getChange(m0^m1);
+   }
+   inline uint8_t getNHit(int i) const {
+      FTK_HitMask data= *(m_ptr+i);
+      uint8_t nhit=
+         (data & 0x11)+
+         ((data>>1)&0x11)+
+         ((data>>2)&0x11)+
+         ((data>>3)&0x11);
+      nhit=(nhit&0xf)+(nhit>>4);
+      return nhit;
+   }
+   inline FTK_HitMask getHitMask(void) const {
+      return *m_ptr;
+   }
+   inline FTK_HitMask const *getPtr(void) const { return m_ptr; }
+ protected:
+   FTK_HitMask __restrict *m_ptr;
+   FTK_HitMask m_mask;
+};
+
+class FTK_HitMaskVector {
+public:
+   inline void setNPattern(uint32_t nPattern) {
+      m_data.reserve(nPattern+3); m_data.resize(nPattern); }
+   inline uint32_t memoryEstimate(void) const {
+      return sizeof(FTK_HitMaskVector)+m_data.capacity()*sizeof(FTK_HitMask);
+   }
+   inline void init(uint32_t first,uint32_t last,FTK_HitMask data) {
+      memset(m_data.data()+first,data,last+1-first);
+   }
+   inline FTK_HitMaskIterator getPointer(uint32_t pattern) {
+      return FTK_HitMaskIterator(m_data.data()+pattern);
+   }
+   inline uint32_t getPatternID(FTK_HitMaskIterator const &ptr) {
+      return ptr.getPtr()-m_data.data();
+   }
+ protected:
+   std::vector<FTK_HitMask> m_data;
+};
+
+#endif
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_RawInput.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_RawInput.h
index bbbc3c296118..5bc2359abbde 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_RawInput.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_RawInput.h
@@ -26,7 +26,7 @@ class FTK_RawInput : public FTKDataInput
   long int m_ntruth_tracks;        // number of truth tracks
 
   int nextFile();
-  
+
 public:
   FTK_RawInput(const FTKPlaneMap *pmap, const FTKPlaneMap *pmap_unused = 0x0);
   FTK_RawInput(const FTK_RawInput& v);
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_SGTrackOutput.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_SGTrackOutput.h
index 2d0ccd14dafb..c3e13c809490 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_SGTrackOutput.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/FTK_SGTrackOutput.h
@@ -25,13 +25,18 @@ private:
   int m_nbanks;
 
   FTKAthTrackContainer **m_tracks; // arrays of tracks
+  FTKAthTrackContainer **m_tracks_pre_hw; // arrays of tracks
   FTKTrackFitterStats **m_TFstats; // TF informations
 
   bool m_storeIncomplete;
 
   FTKAthTrackContainer **m_tracksI; // arrays of tracks
+  FTKAthTrackContainer **m_tracksI_pre_hw; // arrays of tracks
   FTKTrackFitterStats **m_TFstatsI; // TF informations
 
+  FTKAthTrackContainer **m_tracks_pattern; // arrays of tracks
+  FTKAthTrackContainer **m_tracks_hits; // arrays of tracks
+
   StoreGateSvc*  m_storeGate;
 
   mutable MsgStream m_log;
@@ -72,6 +77,7 @@ public:
 
 
   virtual void addTrack(int, const FTKTrack&);
+  virtual void addTrack_pre_hw(int, const FTKTrack&);
   virtual void addNCombs(int ib, int v);
   virtual void addNFits(int ib, int v);
   virtual void addNFitsMajority(int ib, int v);
@@ -87,6 +93,7 @@ public:
   virtual void addNExtrapolatedTracks(int ib, int v);
 
   virtual void addTrackI(int, const FTKTrack&);
+  virtual void addTrackI_pre_hw(int, const FTKTrack&);
   virtual void addNCombsI(int ib, int v);
   virtual void addNFitsI(int ib, int v);
   virtual void addNFitsMajorityI(int ib, int v);
@@ -99,6 +106,9 @@ public:
   virtual void addNFitsBadMajorityI(int ib, int v);
   virtual void addNFitsHWRejectedMajorityI(int ib, int v);
 
+  virtual void addTrack_pattern(int, const FTKTrack&);
+  virtual void addTrack_hits(int, const FTKTrack&);
+
 
 };
 #endif // FTK_SGRoadOutput_H
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter.h
index 59f580740dea..8d1714901129 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter.h
@@ -30,17 +30,20 @@ protected:
   float m_Chi2Cut_vetomaj; // Chi2 for full fits above which majority
 			   // is not attempted; not used by default
 
-  float m_Chi2DofCut; // Cut on the chi2 per degree of freedom; not
+  float m_Chi2DofCutAux; // Cut on the chi2 per degree of freedom for Aux; not
 		      // used by default
 
-  int m_HitWarrior; // 1 means in-road HW enabled, 2 mean global HW (default)
+  float m_Chi2DofCutSSB; // Cut on the chi2 per degree of freedom for SSB; not
+          // used by default
 
-  int m_HitWarrior_first; // 0 means no HW in the 1st stage, 1 means HW within the same raod (default), and 2 means HW within the same sector
+  int m_HitWarrior; // 1 means in-road HW enabled, 2 mean global HW (default)
 
   int m_HW_ndiff; // maximum number of different points
 
   float *m_HW_dev; //[m_ncoords] tolerances for the HW
 
+  bool m_AuxDoctor; // true means enabling Aux Doctor, false means disabling it
+
   int m_keep_rejected; // >0 keep rejected roads (1 HW rej, 2 bad quality)
 
   int m_fit_removed; /* if >0 fit the hit combinations in the removed road.
@@ -81,13 +84,13 @@ protected:
   FTKPlaneMap *m_pmap; // plane-map, needed to know hits dimension
 
   int m_ntracks; // counter of the stored tracks
+  int m_ntracks_pre_hw; // counter of the stored tracks before HW filter
 
   std::list<FTKTrack> m_tracks; // list of output tracks
   std::list<FTKTrack> m_tracks_pre_hw; // list of output tracks before HW filter
-  std::list<FTKTrack> m_sector_tracks; // list of first stage tracks in the same sector
-  std::list<FTKTrack> m_tracks_first; // list of first stage tracks
 
-  int m_processor_stage; // It tells processor() which part to work on for HW within the same sector
+  std::list<FTKTrack> m_tracks_hits; // list of stored tracks that pass hit requirements
+  std::list<FTKTrack> m_tracks_pattern; // list of stored tracks with patterns
 
   int m_ncombs; // number of combinations
   int m_nfits; // number of fits tryied in a road
@@ -114,14 +117,16 @@ protected:
 
   bool m_identify_badhit; // the flag enables the identification of the bad hits for the recovery
 
-  bool m_saveIncompleteTracks; // true if you want to save incompelte tracks
+  bool m_saveStepByStepTracks; // true if you want to save incompelte tracks
 
   virtual void processor_init(int);
   virtual void processor(const FTKRoad &);
   virtual void processor_end(int);
   virtual void compute_truth(const unsigned int&,const FTKRoad &,FTKTrack&) const;
-  int doHitWarriorFilter(FTKTrack&,std::list<FTKTrack>&);
+  int doHitWarriorFilter(FTKTrack&,std::list<FTKTrack>&,bool isfirst=false);
+  int doAuxDoctor(FTKTrack&,std::list<FTKTrack>&);
   std::list<FTKTrack>::iterator removeTrack(std::list<FTKTrack>&, std::list<FTKTrack>::iterator, FTKTrack&, const FTKTrack&,bool isnew=false);
+  std::list<FTKTrack>::iterator removeTrackStage1(std::list<FTKTrack>&, std::list<FTKTrack>::iterator, FTKTrack&, const FTKTrack&,bool isnew=false);
 
 public:
   TrackFitter();
@@ -150,12 +155,12 @@ public:
   void setHitWarrior(int v) { m_HitWarrior = v; }
   int getHitWarrior() const { return m_HitWarrior; }
 
-  void setHitWarriorFirst(int v) { m_HitWarrior_first = v; }
-  int getHitWarriorFirst() const { return m_HitWarrior_first; }
-
   void setHWNDiff(int v) { m_HW_ndiff = v; }
   int getHWNDiff() const { return m_HW_ndiff; }
 
+  void setAuxDoctor(bool v) { m_AuxDoctor = v; }
+  bool getAuxDoctor() const { return m_AuxDoctor; }
+
   void setMaxNcomb(int v) { m_max_ncomb = v; }
   void setMaxNhitsPerPlane(int v) { m_max_nhitsperplane = v; }
   void setMaxTrkout(int v) { m_max_trkout = v; }
@@ -176,6 +181,9 @@ public:
   int getKeepRejected() const { return m_keep_rejected; }
   void setKeepRejected(int v) { m_keep_rejected = v; }
 
+  void setSaveStepByStepTracks(bool flag) { m_saveStepByStepTracks = flag; }
+  bool getSaveStepByStepTracks() const { return m_saveStepByStepTracks; }
+
   void loadHWConf(const char*);
 
   void setChi2Cut(float v) { m_Chi2Cut = v; }
@@ -187,8 +195,11 @@ public:
   void setChi2Cut_vetomaj(float v) { m_Chi2Cut_vetomaj = v; }
   float getChi2Cut_vetomaj() const { return m_Chi2Cut_vetomaj; }
 
-  void setChi2DofCut(float v) { m_Chi2DofCut = v; }
-  float getChi2DofCut() const { return m_Chi2DofCut; }
+  void setChi2DofCutAux(float v) { m_Chi2DofCutAux = v; }
+  float getChi2DofCutAux() const { return m_Chi2DofCutAux; }
+
+  void setChi2DofCutSSB(float v) { m_Chi2DofCutSSB = v; }
+  float getChi2DofCutSSB() const { return m_Chi2DofCutSSB; }
 
   void setBank(int, int, FTKConstantBank*);
 
@@ -203,10 +214,6 @@ public:
     { m_trackoutput_pre_hw = module; }
   FTKTrackOutput* getTrackOutputModule() { return m_trackoutput; }
   FTKTrackOutput* getTrackOutputModulePreHW() { return m_trackoutput_pre_hw; }
-
-  void setSaveIncompleteTracks(bool flag) { m_saveIncompleteTracks = flag; }
-  bool getSaveIncompeteTracks() const { return m_saveIncompleteTracks; }
-
   // output for firmware tests
   //void setFirmwareOutputModule(FTKFirmwareOutput *module) { m_fwoutput = module; }
   //void setNSectorsFWO( int v ) { m_maxsectors_fwo = v; }
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter711.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter711.h
index f28515ab5c87..ad41857e3852 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter711.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/TrackFitter711.h
@@ -129,8 +129,7 @@ protected:
 
   /* void processor_ResolutionMode(const FTKRoad &); */
   /* void processor_ResolutionMode(const FTKRoad &, std::list<FTKTrack> &); */
-   void processor_Incomplete(const FTKRoad &, std::list<FTKTrack> &);
-//  void processor_Incomplete(const FTKRoad &, std::list<FTKTrack> &, std::list<FTKTrack> &);
+  void processor_Incomplete(const FTKRoad &, std::list<FTKTrack> &, std::list<FTKTrack> &);
   void processor_Extrapolate(const FTKRoad &, std::list<FTKTrack> &);
   void processor_SuperExtrapolate(const FTKRoad &, std::list<FTKTrack> &);
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/atlClustering.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/atlClustering.h
deleted file mode 100644
index 888a85bf40f0..000000000000
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/atlClustering.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-#ifndef ATLCLUSTERINGLNF_H
-#define ATLCLUSTERINGLNF_H
-
-/*
- * atlClusteringLNF
- * ---------------
- *
- * Routines to perform clustering in the pixels.
- *
- * 21-11-2007 Alberto Annovi (alberto.annovi@lnf.infn.it)
- *
- */
-
-#include "TrigFTKSim/ftktypes.h"
-#include "TrigFTKSim/FTK_RawInput.h"
-//#include "TrigFTKSim/atlhit_rd.h"
-
-#define GRID_ROW_MAX 21
-#define GRID_COL_MAX 8
-#define hitRowInGrid(gridCntRow, hit) ((hit->getPhiSide() <= gridCntRow + GRID_ROW_MAX/2) && \
-        (hit->getPhiSide() >= gridCntRow - GRID_ROW_MAX / 2))? true : false
-#define hitColInGrid(gridStrCol, hit) (hit->getEtaStrip() < gridStrCol + GRID_COL_MAX)? true : false
-
-#ifdef __cplusplus
-#include <vector>
-#include <set>
-#include <map>
-class FTKRawHit_cmp {
- public:
-  bool operator() (const FTKRawHit *hit1, const FTKRawHit *hit2) const;
-};
-typedef std::vector<FTKRawHit*> hitVector;
-typedef std::map<unsigned int, hitVector> hitsByModuleMap;
-class cluster {
- public:
-  hitVector hitlist; // list of hits that make the cluster
-  FTKRawHit clusterEquiv; // hit equivalent to the cluster
-  FTKRawHit* seed; // hit equivalent to the cluster
-  bool isSafe; // confirmed by ganged pattern recognition 
-  bool isKilled; // ganged pattern recognition suggest to remove this cluster
-
-  ~cluster();
-};
-typedef std::vector<cluster> cluList;
-typedef std::map<unsigned int, cluList*> clustersByModuleMap;
-int hitToModuleId(const FTKRawHit &hit);
-
-extern bool SAVE_CLUSTER_CONTENT;
-extern bool DIAG_CLUSTERING;
-extern int PIXEL_CLUSTERING_MODE;
-const int PIXEL_CLUSTERING_IDEAL=1;
-const int PIXEL_CLUSTERING_IDEAL_APRIL_2014_FIX=2;
-const int PIXEL_CLUSTERING_MIXED=100;
-const int PIXEL_CLUSTERING_REALISTIC=101;
-const int  PIXEL_CLUSTERING_HARDWARE = 200; 
-extern bool IBL3D_REALISTIC;
-extern bool DUPLICATE_GANGED;
-extern bool GANGED_PATTERN_RECOGNITION;
-extern bool SPLIT_BLAYER_MODULES;
-extern bool SCT_CLUSTERING;
-
-extern "C" {
-#endif
-  void atlClusteringBlayer(std::vector<FTKRawHit> &);
-  void atlClusteringLNF(std::vector<FTKRawHit> &);
-  //  void atlClusteringTrack(atltrack *track);
-  int moduleIdToLayer(int modId);
-  int moduleIdToIsPixel(int modId);
-  int moduleIdIsEndcap(int modId);
-  double eta(const FTKRawHit &);
-  int hitIsGanged(const FTKRawHit &);
-  int gangedPartner(const FTKRawHit &);
-  double getDeltaX1A(cluster &); 
-  double getDeltaX2A(cluster &); 
-  int getDeltaXEC1A(cluster &); 
-  int getDeltaXEC2A(cluster &); 
-  int getDeltaYEC1A(cluster &); 
-  int getDeltaYEC2A(cluster &); 
-  int getDeltaY1A(cluster &); 
-  int getDeltaY2A(cluster &);
-  int getDeltaY1B(cluster &); 
-  int getDeltaY2B(cluster &); 
-  	  
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ATLCLUSTERINGLNF_H
diff --git a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/ftkdefs.h b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/ftkdefs.h
index a9cc7f6e0a5b..c0bc03c4c8c8 100644
--- a/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/ftkdefs.h
+++ b/Trigger/TrigFTK/TrigFTKSim/TrigFTKSim/ftkdefs.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef FTKDEFS_H
@@ -55,7 +55,7 @@ namespace ftk {
   const float numberOfPhiPixelsInIblModule = 336.; ///< Number of rows in an IBL module
 
   /**
-   * \namespace ftk::clustering 
+   * \namespace ftk::clustering
    * \brief Default values used for the centroid calculation of a cluster.
    */
   namespace clustering {
@@ -65,7 +65,7 @@ namespace ftk {
       const float xScaleFactorIbl = 8.; ///<TODO
       const float pixelEndCapRPhiCorrection = 25.4*micrometer/phiPitch; ///< TODO - Lorentz angle?
       const float pixelIblRPhiCorrection = 7*micrometer/phiPitch; ///< TODO - Lorentz angle?
-      const float radiusIbl = 35.78; ///< IBL (from fig5 in IBL TDR: (33.25 + 38.31)/2)   
+      const float radiusIbl = 35.78; ///< IBL (from fig5 in IBL TDR: (33.25 + 38.31)/2)
       const float radii[4] = {35.78, 50.5, 88.5, 122.5}; ///< Radii of the 4 layers, starting with IBL, B-Layer, etc.
       const int feChipsInRowPixel = 8; ///< Number of Front-End chips in each pixel module row
       const int rowsInFEChipPerPixelModuleRow = 164; ///<Number of rows in a FE chip of a pixel module
@@ -75,6 +75,14 @@ namespace ftk {
 
   }
 
+  namespace pcm {
+    const int PIXEL_CLUSTERING_IDEAL=1;
+    const int PIXEL_CLUSTERING_IDEAL_APRIL_2014_FIX=2;
+    const int PIXEL_CLUSTERING_MIXED=100;
+    const int PIXEL_CLUSTERING_REALISTIC=101;
+    const int PIXEL_CLUSTERING_HARDWARE = 200;
+  }
+
   const int MOD_ADLER = 65521;
   uint32_t adler32chksum(const void *buf, size_t buflength);
   TString StripFileName(TString path);
diff --git a/Trigger/TrigFTK/TrigFTKSim/python/FTKSimOptions.py b/Trigger/TrigFTK/TrigFTKSim/python/FTKSimOptions.py
index ae6199f30b8c..fb7a213a9ec4 100644
--- a/Trigger/TrigFTK/TrigFTKSim/python/FTKSimOptions.py
+++ b/Trigger/TrigFTK/TrigFTKSim/python/FTKSimOptions.py
@@ -3,16 +3,16 @@
 import PyJobTransforms.trfExceptions as trfExceptions
 import PyJobTransforms.trfArgClasses as trfArgClasses
 
-
-def addTrigFTKAthenaOptions(parser):
-    parser.defineArgGroup('Athena', 'General Athena Options')
-    parser.add_argument('--asetup', group='Athena', type=trfArgClasses.argFactory(trfArgClasses.argSubstep, runarg=False), nargs='+', metavar='substep:ASETUP',
-                        help='asetup command string to be run before this substep is executed')
-    return None
-
+
+def addTrigFTKAthenaOptions(parser):
+    parser.defineArgGroup('Athena', 'General Athena Options')
+    parser.add_argument('--asetup', group='Athena', type=trfArgClasses.argFactory(trfArgClasses.argSubstep, runarg=False), nargs='+', metavar='substep:ASETUP',
+                        help='asetup command string to be run before this substep is executed')
+    return None
+
 def addTrigFTKSimOptions(parser,nsubregions=4):
     parser.defineArgGroup('TrigFTKSim', 'Fast tracker simulation generic options')
-
+
     parser.add_argument('--NBanks', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
                         help='Number of pattern banks', group='TrigFTKSim')
     # Here we set a default value as the merger wants this explicitly
@@ -208,6 +208,8 @@ def addTrigFTKSimTFOptions(parser):
 
     parser.add_argument('--Save1stStageTrks', type=trfArgClasses.argFactory(trfArgClasses.argBool, runarg=True),
                         help='Save 1st stage tracks', group="TrigFTKTrackFitter")
+    parser.add_argument('--SaveStepByStepTrks', type=trfArgClasses.argFactory(trfArgClasses.argBool, runarg=True),
+                        help='Save step-by-step tracks', group="TrigFTKTrackFitter")
 
     parser.add_argument('--loadHWConf_path', type=trfArgClasses.argFactory(trfArgClasses.argString, runarg=True),
                         help='Location of HW configuration file', group='TrigFTKTrackFitter')
@@ -215,11 +217,12 @@ def addTrigFTKSimTFOptions(parser):
                         help="Hit Warrior threshold", group='TrigFTKTrackFitter')
     parser.add_argument('--HitWarrior', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
                         help="Hit Warrior type: 0 none, 1 local, 2 global (def)", group='TrigFTKTrackFitter')
-    parser.add_argument('--FirstStageHitWarrior', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
-                        help="First Stage Hit Warrior type: 0 No First Stage Overlap Removal, 1 Overlap Removal within the Same Road (def), 2 Overlap Removal within the Same Sector", group='TrigFTKTrackFitter')
     parser.add_argument('--HitWarriorMerger', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
                         help="Hit Warrior Merger (merge) type", group='TrigFTKTrackFitter')
 
+    parser.add_argument('--AuxDoctor', type=trfArgClasses.argFactory(trfArgClasses.argBool, runarg=True),
+                        help="Enables Aux Doctor Overlap Removal", group='TrigFTKTrackFitter')
+
     parser.add_argument('--SecondStageFit', type=trfArgClasses.argFactory(trfArgClasses.argBool, runarg=True),
                         help="Enables the second stage fitter", group='TrigFTKTrackFitter')
 
@@ -227,18 +230,15 @@ def addTrigFTKSimTFOptions(parser):
                         help="Print SSB Constants in firmware-style", group='TrigFTKTrackFitter')
 
     parser.add_argument('--dTIBL', type=trfArgClasses.argFactory(trfArgClasses.argFloat, runarg=True),
-                        help="dT for IBL temperature shifts in SSB fit.", group='TrigFTKSim')
+                        help="dT for IBL temperature shifts in SSB fit.", group='TrigFTKTrackFitter')
 
 
     parser.add_argument('--doAuxFW', type=trfArgClasses.argFactory(trfArgClasses.argBool, runarg=True),
-                        help="Enables firmware-style constants", group='TrigFTKSim')
+                        help="Enables firmware-style constants", group='TrigFTKTrackFitter')
     parser.add_argument('--MaxNcomb', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
-                        help="Limit on the number of combinations per road", group='TrigFTKSim')
+                        help="Limit on the number of combinations per road", group='TrigFTKTrackFitter')
     parser.add_argument('--MaxNhitsPerPlane', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
-                        help="limit the number of hits per plane per road", group='TrigFTKSim')
-
-    parser.add_argument("--Save1stStageTrks", type=trfArgClasses.argFactory(trfArgClasses.argBool, runarg=True),
-                        help="Save the tracks after the first stage", group='TrigFTKTrackFitter')
+                        help="limit the number of hits per plane per road", group='TrigFTKTrackFitter')
 
     parser.add_argument('--TRACKFITTER_MODE', type=trfArgClasses.argFactory(trfArgClasses.argIntList, runarg=True),
                         help='track fitter mode', group='TrigFTKTrackFitter', nargs='+')
@@ -254,8 +254,11 @@ def addTrigFTKSimTFOptions(parser):
                         help='when SSFTRDefn=1 (by eta), the min eta', group='TrigFTKTrackFitter')
     parser.add_argument('--SSFTRMaxEta', type=trfArgClasses.argFactory(trfArgClasses.argFloat, runarg=True),
                         help='when SSFTRDefn=1 (by eta), the max eta', group='TrigFTKTrackFitter')
-    parser.add_argument('--Chi2DofCut', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
-                        help='Chi2 cut on second stage tracks', group='TrigFTKTrackFitter')
    
+    parser.add_argument('--Chi2DofCutAux', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
+                        help='Chi2 cut on first stage tracks', group='TrigFTKTrackFitter')
+    parser.add_argument('--Chi2DofCutSSB', type=trfArgClasses.argFactory(trfArgClasses.argInt, runarg=True),
+                        help='Chi2 cut on second stage tracks', group='TrigFTKTrackFitter')
+    
     return None
 
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/scripts/TrigFTKSim_tf.py b/Trigger/TrigFTK/TrigFTKSim/scripts/TrigFTKSim_tf.py
index 2642ed93ef00..1bbbea3e3b36 100755
--- a/Trigger/TrigFTK/TrigFTKSim/scripts/TrigFTKSim_tf.py
+++ b/Trigger/TrigFTK/TrigFTKSim/scripts/TrigFTKSim_tf.py
@@ -80,7 +80,7 @@ def addFTKSimulationArgs(parser):
     parser.add_argument('--ssmapunused_path', type=trfArgClasses.argFactory(trfArgClasses.argString, runarg=True),
                         help='Location of ssmapunused file', group='TrigFTKSim')
     parser.add_argument('--IBLMode',type=trfArgClasses.argFactory(trfArgClasses.argInt,runarg=True),
-                        help='Enalbe the IBL geometry',group='TrigFTKSim')
+                        help='Enable the IBL geometry',group='TrigFTKSim')
     parser.add_argument('--badmap_path', type=trfArgClasses.argFactory(trfArgClasses.argString, runarg=True),
                         help='Location of badmap file', group='TrigFTKSim')
     parser.add_argument('--badmap_path_for_hit', type=trfArgClasses.argFactory(trfArgClasses.argString, runarg=True),
diff --git a/Trigger/TrigFTK/TrigFTKSim/share/FTKCompleteSim_joboptions.py b/Trigger/TrigFTK/TrigFTKSim/share/FTKCompleteSim_joboptions.py
index 60d8904c8e41..83e681609d96 100644
--- a/Trigger/TrigFTK/TrigFTKSim/share/FTKCompleteSim_joboptions.py
+++ b/Trigger/TrigFTK/TrigFTKSim/share/FTKCompleteSim_joboptions.py
@@ -279,7 +279,8 @@ for reg in xrange(0,8) :
 FTKTrackFitter.Chi2Cut         = 17 #Default 17
 FTKTrackFitter.Chi2Cut_Maj     = 14 #Default 0
 FTKTrackFitter.Chi2Cut_VetoMaj = 0 #Default 0
-FTKTrackFitter.Chi2DofCut      = 4 #Default 0
+FTKTrackFitter.Chi2DofCutAux   = 4 #Default 0
+FTKTrackFitter.Chi2DofCutSSB   = 4 #Default 0
 
 FTKTrackFitter.NCoords        = 10 # 10 for 7L, 11 for 8L, 14 for 11L
 FTKTrackFitter.HitWarrior     = 2  #Default 2
diff --git a/Trigger/TrigFTK/TrigFTKSim/share/FTKSim_joboptions.py b/Trigger/TrigFTK/TrigFTKSim/share/FTKSim_joboptions.py
index 0490a7936173..99d02d4de634 100644
--- a/Trigger/TrigFTK/TrigFTKSim/share/FTKSim_joboptions.py
+++ b/Trigger/TrigFTK/TrigFTKSim/share/FTKSim_joboptions.py
@@ -268,7 +268,8 @@ FTKTrackFitter.banksubregion = [0]
 FTKTrackFitter.Chi2Cut         = 17 #Default 17
 FTKTrackFitter.Chi2Cut_Maj     = 14 #Default 0
 FTKTrackFitter.Chi2Cut_VetoMaj = 0 #Default 0
-FTKTrackFitter.Chi2DofCut      = 4 #Default 0
+FTKTrackFitter.Chi2DofCutAux   = 4 #Default 0
+FTKTrackFitter.Chi2DofCutSSB   = 4 #Default 0
 
 FTKTrackFitter.NCoords        = 10 # 10 for 7L, 11 for 8L, 14 for 11L
 FTKTrackFitter.HitWarrior     = 2  #Default 2
diff --git a/Trigger/TrigFTK/TrigFTKSim/share/skeleton.BS_FTK_Creator.py b/Trigger/TrigFTK/TrigFTKSim/share/skeleton.BS_FTK_Creator.py
index 241859de0f56..e1a53d15c6fe 100755
--- a/Trigger/TrigFTK/TrigFTKSim/share/skeleton.BS_FTK_Creator.py
+++ b/Trigger/TrigFTK/TrigFTKSim/share/skeleton.BS_FTK_Creator.py
@@ -55,6 +55,16 @@ FTK_RDO_CreatorAlgo = FTK_RDO_CreatorAlgo()
 #FTK_RDO_CreatorAlgo.OutputLevel = VERBOSE
 FTK_RDO_CreatorAlgo.mergeTrackBName = "FTKMergedTracksStream"
 FTK_RDO_CreatorAlgo.mergedTrackPaths = inputNTUP_FTKFile
+# By definition the direction of IBL locX is:
+#      RAW      : reversed
+#      NTUP_FTK : reversed
+#      RDO      : normal
+#      AOD      : normal
+#  This FTK_RDO_CreatorAlgo is getting FTK tracks from NTUP_FTK and writing RAW
+#  So we need to preserve IBL locX unchanged
+#  (non-reversed RDO are created in Storegate as part of the process, but they are not written).
+#  The reversal comes in the Reco job in FTK_DataProviderSvc 
+FTK_RDO_CreatorAlgo.ReverseIBLlocX=False 
 
 from AthenaCommon.AlgSequence import AlgSequence
 topSeq = AlgSequence()
@@ -69,7 +79,7 @@ rec.doWriteTAG.set_Value_and_Lock(False)
 rec.doTruth.set_Value_and_Lock(False)
 rec.doWriteBS.set_Value_and_Lock(True)
 rec.doESD.set_Value_and_Lock(False)
-
+rec.doWriteESD.set_Value_and_Lock(False)
 ###
 from RecExConfig.RecAlgsFlags import recAlgs
 recAlgs.doTrigger.set_Value_and_Lock(False)
@@ -87,6 +97,7 @@ jobproperties.LArRODFlags.doLArFebErrorSummary.set_Value_and_Lock(False)
 # main jobOption
 include ("RecExCommon/RecExCommon_topOptions.py")
 
+svcMgr.ByteStreamCnvSvc.IsSimulation = False
 StreamBSFileOutput.ItemList = ["FTK_RawTrackContainer#*"]
 
 # Merge with original bytestream
diff --git a/Trigger/TrigFTK/TrigFTKSim/share/skeleton.FTKStandaloneSim.py b/Trigger/TrigFTK/TrigFTKSim/share/skeleton.FTKStandaloneSim.py
index 07d810f8b807..aa5040f28872 100644
--- a/Trigger/TrigFTK/TrigFTKSim/share/skeleton.FTKStandaloneSim.py
+++ b/Trigger/TrigFTK/TrigFTKSim/share/skeleton.FTKStandaloneSim.py
@@ -100,6 +100,26 @@ FTKRoadFinder.DCMatchMethod = 1
 #FTKRoadFinderAlgo.ssmaptsp_path = ssmaptsp_path
 #FTKRoadFinderAlgo.ssmapunused_path = ssmapunused_path
 FTKRoadFinder.ReadFTKHits = False
+#
+# AMcompressionMode : useful settings are 2,3,4,0
+#    2 : U7 compression scheme [fast event loop]
+#    3 : DELTA compression scheme, as stored on disk [best init CPU]
+#    4 : BIT4 compression scheme [slow, best allocated memory]
+#    0 : compromize of U7,DELTA,U32 [performs similar to U7]
+# less useful settings -1,1,5
+#   -1 : DELTA scheme without repacking [similar mode=3]
+#    1 : U32 no compression [fastest event loop, very large memory demand]
+#    5 : alternative delta scheme DELTA2 [performs similar to mode=3]
+#
+# performance for FTKRoadFinderAlgo, barrel tower, ttbar mu=60, 2.5 GHz CPU
+#   setting         -1     0     1     2     3     4     5
+#===========================================================
+# cpu(evt) [ms]    200   170   150   160   190   300   180
+# cpu(init) [s]   20.6  23.1  25.8  25.2  19.9  26.9  23.1
+# VMEM [kb/1000]   662   737  1547   768   695   678   695 
+# alloc [kb/1000]  639   572  1342   605   528   512   528
+
+FTKRoadFinder.AMcompressionMode = 2
 
 # List here the runArgs which need to be translated directly into FTKRoadFinder attributes
 runArgsFromTrfMandatory = [
@@ -160,10 +180,11 @@ runArgsFromTrfOptionalTF = {
     'ITkMode': False,
     'Chi2Cut': 17,
     'Chi2Cut_Maj': 14,
-    'Chi2DofCut': 4, # if >0 the previous values are ignored
+    'Chi2DofCutAux': 4, # if >0 the previous values are ignored
+    'Chi2DofCutSSB': 4, # if >0 the previous values are ignored
     'Chi2Cut_VetoMaj': -1, # no majority veto by default
     'HitWarrior': 2,
-    'FirstStageHitWarrior': 1,
+    'AuxDoctor': False,
     'KeepRejected': 0,
     'FitRemoved': 0,
     'HWNDiff': 6,
@@ -179,7 +200,8 @@ runArgsFromTrfOptionalTF = {
     'SSFTRMinEta': 1.0,
     'SSFTRMaxEta': 1.4,
     'ModuleLUTPath2nd': "",
-    'Save1stStageTrks': False
+    'Save1stStageTrks': False,
+    'SaveStepByStepTrks': False
     }
 
 #JDC:Find files from ConstantsDir, use to set certain attributes
@@ -757,7 +779,8 @@ FTKTagOptions['FitITk'] = {
     'UseCompressedBank': False,
     'SecondStageFit': False,
     'TRACKFITTER_MODE': 1,
-    'Chi2DofCut': 1000000,
+    'Chi2DofCutAux': 1000000,
+    'Chi2DofCutSSB': 1000000,
     'FixEndCapL0': False, 'IBLMode': 0,
     'ITkMode': True,
     'PixelClusteringMode': 1,
@@ -773,7 +796,8 @@ FTKTagOptions['FitITkSaP'] = {
     'UseCompressedBank': False,
     'SecondStageFit': False,
     'TRACKFITTER_MODE': 1,
-    'Chi2DofCut': 1000000,
+    'Chi2DofCutAux': 1000000,
+    'Chi2DofCutSSB': 1000000,
     'IBLMode': 0,
     'ITkMode': True,
     'PixelClusteringMode': 1,
@@ -790,7 +814,9 @@ FTKTagOptions['FitITkDC'] = {
     'CachedBank': True,
     'SecondStageFit': False,
     'TRACKFITTER_MODE': 1,
-    'Chi2DofCut': 1000000,
+
+    'Chi2DofCutAux': 1000000,
+    'Chi2DofCutSSB': 1000000,
     'IBLMode': 0,
     'ITkMode': True,
     'PixelClusteringMode': 1,
@@ -940,6 +966,10 @@ else:
 if hasattr(runArgs,'Save1stStageTrks'):
     FTKTrackFitter.Save1stStageTrks = runArgs.Save1stStageTrks
 
+#check if we want to save step-by-step tracks
+if hasattr(runArgs,'SaveStepByStepTrks'):
+    FTKTrackFitter.SaveStepByStepTrks = runArgs.SaveStepByStepTrks
+
 # check if the second stage is going to be used
 if not hasattr(runArgs,'doAuxFW'):
     FTKTrackFitter.doAuxFW = False
diff --git a/Trigger/TrigFTK/TrigFTKSim/share/skeleton.RDO_FTK_Creator.py b/Trigger/TrigFTK/TrigFTKSim/share/skeleton.RDO_FTK_Creator.py
index 6c0fa20a4c11..ab68e3681f3a 100755
--- a/Trigger/TrigFTK/TrigFTKSim/share/skeleton.RDO_FTK_Creator.py
+++ b/Trigger/TrigFTK/TrigFTKSim/share/skeleton.RDO_FTK_Creator.py
@@ -57,6 +57,14 @@ import os.path
 
 FTK_RDO_CreatorAlgo.mergeTrackBName = "FTKMergedTracksStream"
 FTK_RDO_CreatorAlgo.mergedTrackPaths = inputNTUP_FTKFile
+# By definition the direction of IBL locX is:
+#      RAW      : reversed
+#      NTUP_FTK : reversed
+#      RDO      : normal
+#      AOD      : normal
+#  This FTK_RDO_CreatorAlgo is getting the FTK tracks from NTUP_FTK and writing RDO so
+#  the direction of IBL locX needs to be reversed 
+FTK_RDO_CreatorAlgo.ReverseIBLlocX=True 
 
 from RecExConfig.RecFlags import rec
 rec.doCBNT.set_Value_and_Lock(False)
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringEngine.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringEngine.cxx
new file mode 100644
index 000000000000..236f30a3df19
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringEngine.cxx
@@ -0,0 +1,1247 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TrigFTKSim/FTKClusteringEngine.h"
+#include "TrigFTKSim/FTKSetup.h"
+#include "TrigFTKSim/FTKPMap.h"
+#include "TrigFTKSim/MultiTruth.h"
+#include "TrigFTKSim/ftkdefs.h"
+
+#include <cmath>
+#include <iostream>
+#include <iomanip>
+#include <stack>
+#include <queue>
+
+cluster::~cluster()
+{
+    hitlist.clear();
+}
+
+
+FTKClusteringEngine::FTKClusteringEngine(bool saveClusterContent, bool diagClustering,
+                                         bool sctClustering, bool ibl3DRealistic,
+                                         bool duplicateGanged, bool gangedPatternRecognition,
+                                         bool splitBlayerModules, int pixelClusteringMode) :
+    FTKLogging("FTKClusteringEngine"),
+    m_saveClusterContent(saveClusterContent),
+    m_diagClustering(diagClustering),
+    m_sctClustering(sctClustering),
+    m_ibl3DRealistic(ibl3DRealistic),
+    m_duplicateGanged(duplicateGanged),
+    m_gangedPatternRecognition(gangedPatternRecognition),
+    m_splitBlayerModules(splitBlayerModules),
+    m_pixelClusteringMode(pixelClusteringMode)
+{
+
+}
+
+/*! Function which examines whether a hit belongs to an IBL module.
+ * \param hit the hit
+ * \return true if the hit is on an IBL module, false otherwide
+ */
+bool FTKClusteringEngine::hitOnIBLmodule(const FTKRawHit &hit)
+{
+    return (hit.getModuleType() == ftk::MODULETYPE_IBL3D || hit.getModuleType() == ftk::MODULETYPE_IBL_PLANAR);
+}
+
+
+bool FTKClusteringEngine::sortPixelInput (const std::unique_ptr<FTKRawHit>& i, const  std::unique_ptr<FTKRawHit>& j)
+{
+
+    FTK_FECoordsHit lhit1(*(i.get()));
+    FTK_FECoordsHit lhit2(*(j.get()));
+
+    if (lhit1.fe != lhit2.fe) return lhit1.fe <= lhit2.fe;
+    else if (lhit1.fe == lhit2.fe) {
+        if (lhit1.lcol/2 != lhit2.lcol/2) return lhit1.lcol/2 <= lhit2.lcol/2;
+        else if (lhit1.lcol/2 == lhit2.lcol/2) return lhit1.lrow < lhit2.lrow;
+    }
+
+    return false;
+}
+
+bool FTKClusteringEngine::sortIBLInput(const std::unique_ptr<FTKRawHit>& i, const std::unique_ptr<FTKRawHit>& j)
+{
+    int firstCol  = i->getEtaStrip();
+    int secondCol = j->getEtaStrip();
+    int firstRow  = i->getPhiSide(); // Keisuke 20170314, start from 0
+    int secondRow = j->getPhiSide(); // Keisuke 20170314, start from 0
+    int firstFE  = (firstCol  < ftk::clustering::colsInFEChipPerIblModuleRow) ? 0 : 1;
+    int secondFE = (secondCol < ftk::clustering::colsInFEChipPerIblModuleRow) ? 0 : 1;
+
+    if(firstCol >= ftk::clustering::colsInFEChipPerIblModuleRow)
+      firstCol = firstCol - ftk::clustering::colsInFEChipPerIblModuleRow - 1;
+    if(secondCol >= ftk::clustering::colsInFEChipPerIblModuleRow)
+      secondCol = secondCol - ftk::clustering::colsInFEChipPerIblModuleRow - 1;
+
+    if (firstFE != secondFE) return firstFE > secondFE;
+    else{
+        if(firstCol < ftk::clustering::colsInFEChipPerIblModuleRow/2
+	   || secondCol < ftk::clustering::colsInFEChipPerIblModuleRow/2){
+	  if(firstCol != secondCol) {
+                return firstCol < secondCol;
+	  }
+	  else {
+                return firstRow < secondRow;
+	  }
+        } else {
+	  if(firstCol != secondCol) {
+                return firstCol > secondCol;
+	  }
+	  else {
+                return firstRow < secondRow;
+	  }
+        }
+    }
+    return false;
+}
+
+
+bool FTKClusteringEngine::isSplitCluster(const cluster* clu)
+{
+    for (auto& hit: clu->hitlist) {
+        FTK_ClusterCoordHit chit = FTK_ClusterCoordHit(*hit , clu->seed);
+        if ((chit.ccol >= GRID_COL_MAX - 1) ||  (chit.crow >= (GRID_ROW_MAX - 1)) || ( chit.crow <= 0))
+            return true;
+    }
+
+    return false;
+}
+
+uint32_t FTKClusteringEngine::getModuleId(const FTKRawHit &hit)
+{
+    return hit.getHitType() == ftk::PIXEL ? hit.getIdentifierHash() : 0x8000 + hit.getIdentifierHash();
+}
+
+
+bool FTKClusteringEngine::neighborhood(const FTKRawHit &hit1, const FTKRawHit &hit2)
+{
+    // 1st check same module
+    if (hit1.getIdentifierHash() != hit2.getIdentifierHash()) {
+        Error("neighborhood") << "Hits do not belong in the same cluster" << std::endl;
+        return false;
+    }
+
+    switch (hit1.getHitType()) {
+    case ftk::SCT:
+        if (!m_sctClustering)
+            return false;
+        if (hit1.getEtaStrip() == hit2.getEtaStrip()+hit2.getNStrips()
+            || hit1.getEtaStrip()+hit1.getNStrips() == hit2.getEtaStrip())
+            return true;
+        return false;
+
+    case ftk::PIXEL:
+        /* need a common edge, i.e. contiguity along diagonal is not enough (see below) */
+        if ( (hit1.getEtaStrip() == hit2.getEtaStrip()+1 || hit1.getEtaStrip()+1 == hit2.getEtaStrip())
+             && hit1.getPhiSide() == hit2.getPhiSide())
+            return true;
+        if ( (hit1.getPhiSide() == hit2.getPhiSide()+1 || hit1.getPhiSide()+1 == hit2.getPhiSide())
+             && hit1.getEtaStrip() == hit2.getEtaStrip()) return true;
+
+
+        if (m_diagClustering) { /* Accept contiguity along diagonal as well */
+            if ( (hit1.getEtaStrip() == hit2.getEtaStrip()+1 || hit1.getEtaStrip()+1 == hit2.getEtaStrip())
+                 && (hit1.getPhiSide() == hit2.getPhiSide()+1 || hit1.getPhiSide()+1 == hit2.getPhiSide()) )
+                return true;
+        }
+
+        return false;
+    }
+    return false;
+}
+
+
+int FTKClusteringEngine::buildUpCluster(hitVector& currentHits, cluster& clu)
+{
+    if (clu.hitlist.size()==0) {
+        clu.hitlist.push_back(std::move(currentHits.front()));
+        currentHits.erase(currentHits.begin());
+    }
+
+    /* Now we have a non empty cluster */
+    bool newHitsAdded = false;
+    int distanceis = clu.hitlist.size();
+    hitVector::iterator hitP;
+    for(int i = 0; i < distanceis; i++) {
+        std::unique_ptr<FTKRawHit> hit = std::make_unique<FTKRawHit>(*clu.hitlist.at(i));
+        for (hitP = currentHits.begin(); hitP != currentHits.end(); ) { // loop over hits in module
+            if (neighborhood(*hit, **hitP)) { // if hits are neighborhood
+                clu.hitlist.push_back(std::move(*hitP));
+                currentHits.erase(hitP);
+                distanceis++;
+                hitP = currentHits.begin(); // if a hit is erased then restart the loop
+                newHitsAdded = true;
+            } else {
+                ++hitP; // if hit is not a neighborhood then go to next hit
+            }
+        }
+    }
+
+    // // if at least one hit was added, check for more neighborhood hits
+    if (newHitsAdded && currentHits.size())
+        buildUpCluster(currentHits, clu);
+    return clu.hitlist.size();
+}
+
+
+/*
+ * Group all hits from one module into clusters
+ */
+void FTKClusteringEngine::makeClustersLNF(hitVector& currentHits, cluList& currentClusters)
+{
+    while (currentHits.size()) { // as long as we have hits
+        std::unique_ptr<cluster> clu = std::make_unique<cluster>();
+        clu->isSafe = false;
+        clu->isKilled = false;
+        buildUpCluster(currentHits, *clu.get());
+        currentClusters.push_back(std::move(clu));
+    }
+}
+
+
+void FTKClusteringEngine::makeClusterFromSeed(hitVector& currentHits, cluList& currentClusters, FTKRawHit &seed)
+{
+    if (currentHits.size() > 0)
+    currentHits.erase(std::find_if(currentHits.begin(), currentHits.end(),
+                                   [&](const std::unique_ptr<FTKRawHit>& chit) {
+                                       return seed.getEtaStrip() == (chit.get())->getEtaStrip()
+                                           && seed.getPhiSide() == (chit.get())->getPhiSide()
+                                           && seed.getTot() == (chit.get())->getTot();}));
+
+    std::unique_ptr<cluster> clu = std::make_unique<cluster>();
+    clu->seed = seed;
+    clu->hitlist.push_back(std::move(std::make_unique<FTKRawHit>(seed)));
+    clu->isSafe = false;
+    clu->isKilled = false;
+    buildUpCluster(currentHits, *clu.get());
+    currentClusters.push_back(std::move(clu));
+}
+
+
+void FTKClusteringEngine::makeClustersGridWindow(hitVector& fifo, cluList& currentClusters)
+{
+    boost::circular_buffer<std::unique_ptr<FTKRawHit>> circular_buffer (256);
+    hitVector gridhits;
+    while (!fifo.empty() || !circular_buffer.empty()) {
+        FTKRawHit seed = gridAUTH(circular_buffer, fifo, gridhits);
+        makeClusterFromSeed(gridhits, currentClusters, seed);
+
+        for(auto& hit: gridhits) {
+            circular_buffer.push_back(std::move (hit));
+        }
+
+        gridhits.clear();
+    }
+}
+
+
+bool FTKClusteringEngine::gangedHitHasNeighborhood(const FTKRawHit &hit, const cluster* clu, hitVector &connectedHits)
+{
+    bool hasNeighborhood = false;
+    int phi = hitIsGanged(hit);
+    if (phi) { // check hit is ganged
+        int eta = hit.getEtaStrip();
+        for (auto& chit: clu->hitlist) {
+            if ( eta != chit->getEtaStrip() )
+                continue;
+            if ( abs(phi - chit->getPhiSide() ) != 1 )
+                continue;
+            hasNeighborhood = true;
+            std::unique_ptr<FTKRawHit> tmpHit = std::make_unique<FTKRawHit>();
+            tmpHit->setHitType( ftk::PIXEL );
+            tmpHit->setModuleType( hit.getModuleType());
+            tmpHit->setEtaStrip( eta );
+            tmpHit->setLayer( hit.getLayer() );
+            tmpHit->setPhiSide( gangedPartner(hit) );
+            connectedHits.push_back( std::move(tmpHit) ); // store connected hit pointer
+        } // end of nested loop over hits
+    } //end of "if (phi)"
+    return hasNeighborhood;
+}
+
+
+bool FTKClusteringEngine::findConnectedGanged(const std::unique_ptr<cluster> &clu, hitVector &connectedHits)
+{
+    bool hasNeighborhood = false;
+    for (auto& hit: clu->hitlist) {
+      if ( gangedHitHasNeighborhood(*hit, clu.get(), connectedHits) ) {
+            hasNeighborhood = true;
+            break;
+        }
+    }
+
+    return hasNeighborhood;
+}
+
+
+bool FTKClusteringEngine::isKilled(const std::unique_ptr<cluster>& clu, const hitVector &connectedHits)
+{
+    bool isKilled = false;
+    for (auto& hit: clu->hitlist) {
+        if ( !hitIsGanged(*hit) ) continue;
+        for (auto& chit: connectedHits) {
+            if ( (*chit).getPhiSide() == (*hit).getPhiSide()
+                 && (*chit).getEtaStrip() == (*hit).getEtaStrip() )
+                isKilled =  true;
+        }
+    } // loop over hits in cluster
+
+    return isKilled;
+}
+
+
+void FTKClusteringEngine::averageCluster(std::unique_ptr<cluster>& clu)
+{
+    const unsigned int &nHits = clu->hitlist.size();
+
+    FTKRawHit &av = clu->clusterEquiv; ///< get pointer to clusterEquivalent
+    FTKRawHit first = *(clu->hitlist.front()); ///< get 1st hit
+
+    /// reset values for clusterEquivalent (alias av)
+    av.reset();
+    av.setX(0);
+    av.setY(0);
+    av.setZ(0);
+    av.setIdentifierHash(first.getIdentifierHash());
+    av.setHitType(first.getHitType());
+    av.setModuleType(first.getModuleType());
+    av.setBarrelEC(first.getBarrelEC());
+    av.setLayer(first.getLayer());
+    av.setPhiModule(first.getPhiModule());
+    av.setEtaModule(first.getEtaModule());
+    av.setEtaStrip(0);
+    av.setNStrips(0);
+    av.setEtaWidth(0);
+    av.setPhiWidth(0);
+    av.setIncludesGanged(false);
+
+    int tmp;
+    int etaMax = -1;
+    int etaMin = 4000;
+    int phiMax = -1;
+    int phiMin = 4000;
+    int rowMin = 99999; //int(2*(design->width()/design->phiPitch()))+1;;
+    int rowMax = 0;
+    int colMin = 99999; //int(2*(design->length()/design->etaPitch()))+1;
+    int colMax = 0;
+    int qRowMin = 0;
+    int qRowMax = 0;
+    int qColMin = 0;
+    int qColMax = 0;
+
+    hitVector::iterator p;
+    /// precalculate values for case m_pixelClusteringMode>0
+    int BarrelEndCap = first.getBarrelEC();
+
+    //Calculate the active layer. Start with the layer of the hit. In case
+    // always count IBL as layer0 and BLayer as layer1
+    int layer = first.getLayer();
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    bool isPixelmodule = !isIBLmodule;
+    if (FTKSetup::getFTKSetup().getIBLMode()==0)
+        layer++;
+    float radius = ftk::clustering::radii[layer];
+
+    //Default values for a pixel module. They are modified for IBL.
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInPixelModule;
+    float lengthOfPixelModuleInUmPixels = ftk::lengthOfPixelModuleIn400umPixels;
+    float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
+    // FlagAA: 2015-01-29 making default the units of 6.25um for r-phi coordinates
+    float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
+    float pixXScaleFactor = ftk::clustering::xScaleFactorPixel;
+    float etaModule = first.getEtaModule()-6;
+    // FlagAA 2013-07-31: IBL code assumes fully planar geometry as in mc12+IBL
+    // This will change for the real detector!!!
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+        etaPitch = ftk::etaPitchIbl;
+        numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInIblModule;
+        lengthOfPixelModuleInUmPixels = ftk::lengthOfIblModuleIn250umPixels;
+        moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
+        pixYScaleFactor = ftk::clustering::yScaleFactorIbl; ///<multiply by 10 to count in unit of 25um
+        pixXScaleFactor = ftk::clustering::xScaleFactorIbl;
+        etaModule = first.getEtaModule()-8;
+        if( first.getModuleType() == ftk::MODULETYPE_IBL3D && m_ibl3DRealistic ) {
+            sensorThickness = 230*ftk::micrometer;
+            moduleActiveLength = 80*250;
+            numberOfEtaPixelsInModule = ftk::clustering::colsInFEChipPerIblModuleRow;
+        }
+    }
+    bool hasGanged = false;
+
+    switch (av.getHitType()) {
+    case ftk::SCT: {
+        int firstStrip =  99999;
+        int lastStrip  = -99999;
+        av.setPhiSide(first.getPhiSide());
+        for (const auto &hit: clu->hitlist) {
+            av.addX(hit->getX());
+            av.addY(hit->getY());
+            av.addZ(hit->getZ());
+            if (hit->getEtaStrip() < firstStrip)
+                firstStrip = hit->getEtaStrip();
+            if (hit->getEtaStrip()+hit->getNStrips()-1 > lastStrip)
+                lastStrip = hit->getEtaStrip() + hit->getNStrips() - 1;
+            av.addEtaStrip(hit->getEtaStrip());
+        }
+        float stripNumberFloat = (firstStrip*1.+lastStrip)/2;
+        //(av.getEtaStrip()*1.)/nHits;
+        av.setEtaStrip( static_cast<int>(stripNumberFloat) );
+        av.setDeltaPhi( stripNumberFloat - static_cast<int>(stripNumberFloat) );
+        // The convention used for SCT is that we are providing as output
+        // the cluster center minus half a strip (i.e. use the left edge of strip for a single strip cluster)
+        // where output = av.setEtaStrip + av.setDeltaPhi
+        av.setStripCoordinate(firstStrip+lastStrip);
+        av.setColumnCoordinate( 0 );
+        av.setDeltaEta(0);
+        av.setNStrips(lastStrip+1-firstStrip);
+        av.setEtaWidth(1);
+        av.setPhiWidth(lastStrip+1-firstStrip);
+        break; // end of SCT
+    }
+    case ftk::PIXEL: {
+        av.setPhiSide(0); // eta is reset a few lines above
+
+        if (m_pixelClusteringMode == 0) {
+            for (const auto& hit: clu->hitlist) { //loop over hits in cluster
+                if (m_saveClusterContent) { // if enabled the cluster also stores also the single channels
+                    FTKRawHit tmpch = *hit;
+                    // set the barcode of the single channel, this may allow a very refined debugging of
+                    // the cluster content accounting for the single barcode of each channel
+                    MultiTruth mt;
+                    MultiTruth::Barcode uniquecode(tmpch.getEventIndex(),tmpch.getBarcode());
+                    mt.maximize(uniquecode,tmpch.getBarcodePt());
+                    tmpch.setTruth(mt);
+                    av.addChannel(tmpch);
+                }
+                av.addX(hit->getX());
+                av.addY(hit->getY());
+                av.addZ(hit->getZ());
+                av.addPhiSide(hit->getPhiSide());   // phi index
+                // pixels are counted starting from 0 (left edge) and not 0.5 (center position)
+                // if only pixel 0 is hit the output value will be 0 and not 0.5 (pixel center)
+                av.addEtaStrip(hit->getEtaStrip()); // eta index
+            }
+            tmp = static_cast<int>(round((av.getEtaStrip()*1.)/nHits));
+            av.setDeltaEta((av.getEtaStrip()*1.)/nHits-tmp);
+            av.setEtaStrip(tmp);
+            tmp = static_cast<int>(round((av.getPhiSide()*1.)/nHits));
+            av.setDeltaPhi((av.getPhiSide()*1.)/nHits-tmp);
+            av.setPhiSide(tmp);
+            break;
+        }
+
+        /* For m_pixelClusteringMode > 0
+         * calculate cluster center following code at line 701 of
+         * https://svnweb.cern.ch/trac/atlasoff/browser/InnerDetector/InDetRecTools/SiClusterizationTool/trunk/src/MergedPixelsTool.cxx#L701
+         * I.e. posStrategy == 1
+         * I.e. use charge imbalance between the two outer most ros (columns) to calculate the centroid
+         * In this code I'll use etaTrack instead of pixel eta for simplicity
+         */
+
+        for (auto& hit: clu->hitlist) { //loop over hits in cluster
+            if (m_saveClusterContent) { // if enabled the cluster also stores also the single channels
+                FTKRawHit tmpch = *hit;
+                // set the barcode of the single channel, this may allow a very refined debugging of
+                // the cluster content accounting for the single barcode of each channel
+                MultiTruth mt;
+                MultiTruth::Barcode uniquecode(tmpch.getEventIndex(),tmpch.getBarcode());
+                mt.maximize(uniquecode,tmpch.getBarcodePt());
+                tmpch.setTruth(mt);
+                av.addChannel(tmpch);
+            }
+
+            av.addX(hit->getX());
+            av.addY(hit->getY());
+            av.addZ(hit->getZ());
+
+            int row = hit->getPhiSide();
+            int col = hit->getEtaStrip();
+            int tot = hit->getTot(); // ToT for pixels
+            if (!isIBLmodule && pixelRowIsGanged(row))
+                hasGanged = true;
+
+            if (isPixelmodule) {
+                // account for 600um pixels in the centroid calculation
+                // will use units of 100um and the convert to normal pixel units below
+                // will also indicate the center of the pixel instead of the left edge
+                // considering center of pixel along eta (left (or top if you prefer) edge along phi)
+                // each FE number is worth 19*400um pixels (400um*16 + 600um*2)
+                // multiply FE column by 4 to convert to 100um units
+                int FEnumber = col/ftk::clustering::colsInFEChipPerPixelModuleRow;
+                int FEcolumn = col%ftk::clustering::colsInFEChipPerPixelModuleRow;
+
+                col = FEnumber*(ftk::clustering::colsInFEChipPerPixelModuleRow+1) + FEcolumn;
+                col *= pixYScaleFactor;
+                col += pixYScaleFactor/2; // add half a pixel to align to pixel center (assume normal 400um pixel)
+                col += pixYScaleFactor/2; // assume 1<=FEcolumn<=16 add half a pixel coming from 600um pixel in FEcolumn==0
+                if (FEcolumn==0) col -= pixYScaleFactor/4; // correct position for first column in FE chip
+                if (FEcolumn==(ftk::clustering::colsInFEChipPerPixelModuleRow-1)) col += pixYScaleFactor/4; // correct position for last column in FE chip
+            } else if (isIBLmodule) { // IBL case
+                //Modifications have to be made to include 3d modules
+                int orig_col = col;
+                col *= pixYScaleFactor; // use units of 25um
+                col += pixYScaleFactor/2; // add half a pixel to align to pixel center
+                if((hit->getModuleType() == ftk::MODULETYPE_IBL3D && m_ibl3DRealistic) || !m_ibl3DRealistic){
+                    if (orig_col==0) col += pixYScaleFactor/2; // add half pixel (500um pixel in col0)
+                    if (orig_col>0) col += pixYScaleFactor; // add a pixel (500um pixel in col0)
+
+                    // for 3D modules only
+                    // if (orig_col==79) col += pixYScaleFactor*5/10; // add 5/10 of pixel i.e. 100um (500um pixel in col79)
+
+                    // for planar modules only
+                    if (orig_col==79) col += pixYScaleFactor*4/10; // add 4/10 of pixel i.e. 100um (450um pixel in col79)
+                    if (orig_col==80) col += pixYScaleFactor*12/10; // add 12/10 of pixel i.e. 300um (450um pixel in col79 and col80)
+                    if (orig_col>80) col += pixYScaleFactor*16/10; // add 16/10 of pixel i.e. 400um (450um pixel in col79 and col80)
+                    if (orig_col==159) col += pixYScaleFactor/2; // add half pixel (500um pixel in col159)
+                }
+            }
+            row *= pixXScaleFactor;
+
+            if (row == rowMin) qRowMin += tot;
+            if (row < rowMin){
+                rowMin = row;
+                qRowMin = tot;
+            }
+
+            if (row == rowMax) qRowMax += tot;
+            if (row > rowMax){
+                rowMax = row;
+                qRowMax = tot;
+            }
+
+            if (col == colMin) qColMin += tot;
+            if (col < colMin){
+                colMin = col;
+                qColMin = tot;
+            }
+
+            if (col == colMax) qColMax += tot;
+            if (col > colMax){
+                colMax = col;
+                qColMax = tot;
+            }
+
+            int phi = hit->getPhiSide(); // ROW // JAA updated 13 March 2017 to remove +1 as above
+            // int phi = (*p)->getPhiSide(); // ROW
+            int eta = hit->getEtaStrip();          // COLUMN
+
+            if (eta > etaMax) etaMax = eta;
+            if (eta < etaMin) etaMin = eta;
+            if (phi > phiMax) phiMax = phi;
+            if (phi < phiMin) phiMin = phi;
+            av.addTot(first.getTot()); // sum ToT for pixel clusters
+        }
+        av.setEtaWidth(etaMax-etaMin+1);
+        av.setPhiWidth(phiMax-phiMin+1);
+
+        // calculate eta index and eta delta
+        double eta_average, phi_average;
+        eta_average = (colMin + colMax) / 2.;
+        phi_average = (rowMin + rowMax) / 2.;
+
+        if (m_pixelClusteringMode == ftk::pcm::PIXEL_CLUSTERING_HARDWARE) {
+            float etaRow = -1;
+            float etaCol = -1;
+            if(qRowMin+qRowMax > 0)
+                etaRow = qRowMax/static_cast<float>(qRowMin+qRowMax);
+            if(qColMin+qColMax > 0)
+                etaCol = qColMax/static_cast<float>(qColMin+qColMax);
+            ///	      double test = 0;
+            int etaRow32 = 0;
+            int etaCol32 =0;
+            etaRow32 = lround(etaRow*32);
+            etaCol32 = lround(etaCol*32);
+            int posStrategy = 1;
+            if(posStrategy == 1 && !hasGanged && etaRow>0 && etaCol > 0){
+                if (BarrelEndCap==0) {
+		  phi_average+= lround((getDeltaX1A(clu.get())+(getDeltaX2A(clu.get()))*etaRow32)/1024.); //  >>10;
+
+                    if ( (etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5) > 0){
+                        if ( sensorThickness*((etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5)
+                                              * moduleActiveLength / radius)>etaPitch) {
+                            ///		    test = etaPitch;
+                            eta_average+= pixYScaleFactor*(etaCol-0.5);
+                            eta_average = lround(eta_average);
+                        }
+                        else
+			  eta_average+= lround((getDeltaY1A(clu.get())+getDeltaY2A(clu.get())*etaCol32
+						+ getDeltaY1B(clu.get())*(colMin+colMax)
+						+ getDeltaY2B(clu.get())*etaCol32*(colMin+colMax))/2048.);
+                    }
+                    else{
+                        if ( sensorThickness*(-1*(etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5)
+                                              * moduleActiveLength / radius)>etaPitch) {
+                            eta_average += pixYScaleFactor*(etaCol - 0.5);
+                            eta_average = lround(eta_average);
+                        }
+                        else
+			  eta_average -= lround((getDeltaY1A(clu.get())+getDeltaY2A(clu.get())*etaCol32
+						 + getDeltaY1B(clu.get())*(colMin+colMax)
+						 + getDeltaY2B(clu.get())*etaCol32*(colMin+colMax)) / 2048.);
+                    }
+
+                }
+
+                else{
+		  phi_average +=  lround((getDeltaXEC1A(clu.get())+getDeltaXEC2A(clu.get())*etaRow32)/1024.);
+		  eta_average +=  lround((getDeltaYEC1A(clu.get())+getDeltaYEC2A(clu.get())*etaCol32)/1024.);
+
+                }
+
+            }
+        }
+        //Correction to the eta_average and phi_average used for
+        //m_pixelClusteringMode 1 and 100
+        if (m_pixelClusteringMode <= ftk::pcm::PIXEL_CLUSTERING_MIXED) {
+            float pixelEstimateCotTheta = -9999.;
+
+            /* The next lines calculate CotTheta of a hypothetic track starting from ATLAS (0,0,0)
+             * and crossing the center of the bounding box of the cluster.
+             * The Z global position is estimated as: module Z position + cluster Z position within the module.
+             *  The radius is a fixed costant depending on the layer. It could be better estimated accounting
+             *  also for the rphi position within the module.
+             */
+            pixelEstimateCotTheta = (etaModule+(rowMin+rowMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5)
+                * moduleActiveLength / radius;
+            if (m_pixelClusteringMode>=ftk::pcm::PIXEL_CLUSTERING_IDEAL_APRIL_2014_FIX) /* Fixing an error in the formula */
+                pixelEstimateCotTheta = (etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5)
+                    * moduleActiveLength / radius;
+
+
+            // Compute eta for charge interpolation correction (if required)
+            // Two pixels may have tot=0 (very rarely, hopefully)
+            float etaRow = -1;
+            float etaCol = -1;
+            if(qRowMin+qRowMax > 0)
+                etaRow = qRowMax/float(qRowMin+qRowMax);
+            if(qColMin+qColMax > 0)
+                etaCol = qColMax/float(qColMin+qColMax);
+
+            // Charge interpolation. Very rough guess (one can do better with
+            // candidate track information later) TL
+            //      bool hasGanged = av.getIncludesGanged();
+            float deltax = 0;
+            float deltay = 0;
+            if (BarrelEndCap==0) { //pixelID.is_barrel(elementID)){
+                deltax = 30*ftk::micrometer*(sensorThickness/(250*ftk::micrometer));
+                deltay = sensorThickness*fabs(pixelEstimateCotTheta);
+                if(deltay > etaPitch ){
+                    deltay = etaPitch;
+                }
+            } else {
+                deltax = 10*ftk::micrometer*sqrt(sensorThickness/(250*ftk::micrometer));
+                deltay = 10*ftk::micrometer*sqrt(sensorThickness/(250*ftk::micrometer));
+            }
+
+            // Width of the region of charge sharing. For disks assume normal incidence: delta is small, due to diffusion
+            // of drifting charges in silicon. For barrel, assume 10 deg. incidence in Rphi, in z compute from pseudorapidity
+            // This may be improved with better parameterization, but it is probably better to use candidate track information
+            // later in reconstruction. TL
+            // Values are made dependent on the sensor thickness to accomodate // different sensors layout. AA
+            //    Point3D<double> globalPos = element->globalPosition(centroid);
+            //    InDetDD::SiLocalPosition totCorrection(0,0,0);
+            int posStrategy = 1; //Same as posStrategy == 1 in InDetRecTools/SiClusterizationTool/trunk/src/MergedPixelsTool.cxx#L701
+            if(posStrategy == 1 && !hasGanged && etaRow>0 && etaCol > 0){
+                phi_average += pixXScaleFactor*deltax*(etaRow-0.5)/ftk::phiPitch;
+                eta_average += pixYScaleFactor*deltay*(etaCol-0.5)/etaPitch;
+            }
+        }
+
+        if (phi_average<0) {
+            Error("averageCluster") << "phi_average < 0" << std::endl;
+            phi_average = 0;
+        }
+        if (eta_average<0) {
+            Error("averageCluster") << "eta_average < 0" << std::endl;
+            eta_average = 0;
+        }
+
+        if (BarrelEndCap != 0)
+            phi_average += ftk::clustering::pixelEndCapRPhiCorrection*pixXScaleFactor;
+        av.setRowCoordinate( lround(phi_average) );
+        av.setColumnCoordinate( lround(eta_average) );
+        av.setSplit(false);
+        if (m_pixelClusteringMode >= ftk::pcm::PIXEL_CLUSTERING_MIXED && isSplitCluster(clu.get()))
+            av.setSplit(true);
+
+        eta_average *= numberOfEtaPixelsInModule/lengthOfPixelModuleInUmPixels/pixYScaleFactor;
+        phi_average /= pixXScaleFactor;
+
+        double delta;
+        delta = eta_average - static_cast<int>(eta_average);
+        av.setDeltaEta(delta);
+        av.setEtaStrip( static_cast<int>(eta_average));
+        delta = phi_average - static_cast<int>(phi_average);
+        av.setDeltaPhi(delta);
+        av.setPhiSide( static_cast<int>(phi_average) );
+
+        break; // end of PIXEL
+    }
+    default:
+        break;
+    } // end of switch
+
+    // finally divide by nHits
+    av.divX(nHits);
+    av.divY(nHits);
+    av.divZ(nHits);
+
+    // AB - perform geant parent matching and store with the cluster
+    // data.  this involves passing all raw hits associated with the
+    // cluster to a MultiTruth which will be stored with the hit
+    // when it is converted to an FTKHit.
+    MultiTruth mt;
+    for( hitVector::iterator ihit=clu->hitlist.begin(), fhit=clu->hitlist.end(); ihit!=fhit; ++ihit ) {
+        // record highest pt contribution to the combination (cluster)
+        if( (*ihit)->getTruth() ) {
+            mt.maximize( *((*ihit)->getTruth()) );
+        } else {
+            MultiTruth::Barcode uniquecode((*ihit)->getEventIndex(),
+                                           (*ihit)->getBarcode());
+            mt.maximize(uniquecode,(*ihit)->getBarcodePt());
+        }
+    } // end record truth for each raw channel in the cluster
+    clu->clusterEquiv.setTruth(mt);
+}
+
+void FTKClusteringEngine::atlClusteringBlayer(std::vector<FTKRawHit> &hits) {
+    /*
+     * Split blayer modules in half along phi
+     * this effectively makes 22*2=44 modules along phi!
+     */
+    if(!m_splitBlayerModules) return;
+    for(unsigned int i = 0; i < hits.size(); i++) {
+#define HIT hits[i]
+        // AK BLAYER : change # modules in barrel blayer from 22 to 44:
+        if(HIT.getIsPixel() && HIT.getBarrelEC()==ftk::BARREL && HIT.getLayer()==0) {
+            HIT.setPhiModule(HIT.getPhiModule()*2);
+            // mid-module sector division: assume SS=20 or 10.
+            // Then the division is right at SS boundary
+            if(HIT.getPhiSide()>159) HIT.setPhiModule(HIT.getPhiModule()+1); // HARDCODED (328/2 rounded to SS=16)
+        }
+#undef HIT
+    }
+}
+
+
+void FTKClusteringEngine::realisticPixelDecoder(hitVector &currentHits)
+{
+    std::stack<std::unique_ptr<FTKRawHit>> lifo;
+    std::queue<std::unique_ptr<FTKRawHit>> fifo;
+    bool getIsIBL = hitOnIBLmodule(*currentHits.front());
+    if (getIsIBL)
+        std::cout << "yep, ibl module" << std::endl;
+
+    if(!getIsIBL) {
+        if (currentHits.size() > 1)
+            std::stable_sort(currentHits.begin(), currentHits.end(), sortPixelInput);
+
+        for(auto& hit: currentHits) {
+            if ((*hit).getPhiSide() < ftk::clustering::rowsInFEChipPerPixelModuleRow) {
+                fifo.push( std::move(hit) );
+            }
+            else {
+                lifo.push( std::move(hit) );
+            }
+        }
+
+        currentHits.clear();
+
+        while(!lifo.empty() && !fifo.empty()){
+            if ((lifo.top().get())->getEtaStrip() <= (fifo.front().get())->getEtaStrip()) {
+                currentHits.push_back( std::move(lifo.top()) );
+                lifo.pop();
+            }
+            else {
+                currentHits.push_back(std::move(fifo.front()));
+                fifo.pop();
+            }
+        }
+
+        while(!lifo.empty()) {
+            currentHits.push_back( std::move(lifo.top()) );
+            lifo.pop();
+        }
+        while(!fifo.empty()) {
+            currentHits.push_back( std::move(fifo.front()) );
+            fifo.pop();
+        }
+    } else {
+        std::stack<std::unique_ptr<FTKRawHit>> lifo_planar;
+        std::queue<std::unique_ptr<FTKRawHit>> fifo_planar;
+
+        //invert row coordinates
+        for(auto& hit: currentHits) {
+            std::unique_ptr<FTKRawHit> h = std::make_unique<FTKRawHit>(*hit);
+            h->setPhiSide( 335 - (*hit).getPhiSide() );
+            h->setEtaStrip( (*hit).getEtaStrip()) ;
+            hit.swap(h);
+        }
+
+        if (currentHits.size() > 1)
+            std::stable_sort(currentHits.begin(), currentHits.end(), sortIBLInput);
+
+        for(auto& hit: currentHits) {
+            if ((*hit).getEtaStrip() < ftk::clustering::colsInFEChipPerIblModuleRow/2)
+                fifo.push(std::move(hit));
+            else if ((*hit).getEtaStrip() >= ftk::clustering::colsInFEChipPerIblModuleRow/2
+                     && (*hit).getEtaStrip() < ftk::clustering::colsInFEChipPerIblModuleRow)
+                lifo.push(std::move(hit));
+            else if ((*hit).getEtaStrip() >= ftk::clustering::colsInFEChipPerIblModuleRow
+                     && (*hit).getEtaStrip() < ftk::clustering::colsInFEChipPerIblModuleRow * 3/2)
+                fifo_planar.push(std::move(hit));
+            else if ((*hit).getEtaStrip() >= ftk::clustering::colsInFEChipPerIblModuleRow * 3/2
+                    && (*hit).getEtaStrip() < 2 * ftk::clustering::colsInFEChipPerIblModuleRow)
+                lifo_planar.push(std::move(hit));
+    }
+
+        currentHits.clear();
+
+        while(!fifo.empty()){
+            currentHits.push_back( std::move(fifo.front()) );
+            fifo.pop();
+        }
+
+        while(!lifo.empty()) {
+            currentHits.push_back(std::move (lifo.top()) );
+            lifo.pop();
+        }
+
+        while(!fifo_planar.empty()) {
+            currentHits.push_back(std::move(fifo_planar.front()) );
+            fifo_planar.pop();
+        }
+
+        while(!lifo_planar.empty()) {
+            currentHits.push_back(std::move(lifo_planar.top()) );
+            lifo_planar.pop();
+        }
+    }
+
+}
+
+FTKRawHit FTKClusteringEngine::gridAUTH(boost::circular_buffer<std::unique_ptr<FTKRawHit>> &cb,
+                                                         hitVector &fifo, hitVector &gridhits)
+{
+
+    //seed is set from cb if there are hits and from
+    //fifo if the seed is empty.
+    std::unique_ptr<FTKRawHit> seed;
+    if (cb.size() == 0){
+        seed = std::make_unique<FTKRawHit>(*fifo.front());
+    }
+    else if (cb.size() != 0) {
+        seed = std::make_unique<FTKRawHit>(*cb.front());
+        for(auto& cbi: cb) {
+            if ((*cbi).getEtaStrip() < (*seed).getEtaStrip())
+                seed = std::make_unique<FTKRawHit>(*cbi);
+            else if ((*cbi).getEtaStrip() == (*seed).getEtaStrip()) {
+                if ((*cbi).getPhiSide() < (*seed).getPhiSide() )
+                    seed = std::make_unique<FTKRawHit>(*cbi);
+            }
+        }
+    }
+
+    //step 2: set grid window limits
+    int gridStrCol = ((*seed).getEtaStrip() % 2 != 0) ? (*seed).getEtaStrip() - 1 : (*seed).getEtaStrip();
+    int gridCntRow = (*seed).getPhiSide();
+
+    //step 3: put hits from cb to the grid window
+    int dist = distance(cb.begin(), cb.end());
+    for(int i = 0; i < dist; i++) {
+        if (!hitColInGrid(gridStrCol, cb.front())) {
+            cb.pop_front();
+            continue;
+        }
+        if (hitRowInGrid(gridCntRow, cb.front())) {
+            gridhits.push_back(std::move(cb.front()));
+        }
+        else {
+            cb.push_back(std::move(cb.front()));
+        }
+        cb.pop_front();
+    }
+
+    //step 4: put hits from fifo to the grid window
+    std::vector<std::unique_ptr<FTKRawHit>>::iterator hit = fifo.begin();
+    while (hit != fifo.end()) {
+        if (!hitColInGrid(gridStrCol, (*hit).get() )) {
+            break;
+        }
+        if (hitRowInGrid(gridCntRow, (*hit).get())) {
+            gridhits.push_back(std::move(*hit));
+        }
+        else {
+            cb.push_back(std::move(*hit));
+        }
+        fifo.erase(hit);
+    }
+
+    return *seed.get();
+}
+
+
+
+/*!
+ * Function responsible for hit clustering and the subsequent centroid
+ * calculation
+ * \param hits hits which will be clustered
+ * \return void
+ */
+void FTKClusteringEngine::atlClusteringLNF(std::vector<FTKRawHit> &hits)
+{
+    /*
+     * Step 1: Organize the hits by the module they belong to. Furthermore, the
+     * ganged hits are duplicated, if requested. The copy constructor is used,
+     * instead of manually assigning each variable.
+     */
+    hitsByModuleMap hitsByModule; ///< store hits by module
+    std::vector<FTKRawHit> gangedPixelList; ///< vector of ganged pixels
+    gangedPixelList.reserve(hits.size()); // reserve memory in excess
+
+    for(const auto& hit: hits) {
+        int modId = getModuleId(hit);
+        if (modId<0)
+            Error("atlClusteringLNF") << "modId < 0" << std::endl;
+        hitsByModule[modId].push_back( std::make_unique<FTKRawHit>(hit) );
+        if (m_duplicateGanged && hitIsGanged(hit)) {
+            gangedPixelList.push_back( hit );
+            FTKRawHit& lastPointer = gangedPixelList.back();
+            lastPointer.setPhiSide(gangedPartner( hit ));
+            hitsByModule[modId].push_back( std::make_unique<FTKRawHit>(lastPointer) );
+        }
+    }
+
+    /*
+     * Step 2: build the list of clusters.
+     * The ideal clustering is going to be used in the following cases:
+     * 1. m_pixelClusteringMode is less than 100 (PIXEL_CLUSTERING_MIXED)
+     * 2. The module is not a pixel module
+     */
+    clustersByModuleMap clustersByModule; ///< store clusters by module
+    for (auto& module: hitsByModule) { // loop over modules
+        int modId = module.first;
+        hitVector currentHits  = std::move(module.second);
+
+        cluList currentClusters; // instantiate cluster list
+
+        if (currentHits.front()->getIsSCT()){
+            makeClustersLNF(currentHits, currentClusters); // use ideal clustering
+        }
+        else if(currentHits.front()->getIsPixel()) {
+	  if (m_pixelClusteringMode < ftk::pcm::PIXEL_CLUSTERING_MIXED) {
+                makeClustersLNF(currentHits, currentClusters);
+            }
+	  else if (m_pixelClusteringMode >= ftk::pcm::PIXEL_CLUSTERING_MIXED) {
+                realisticPixelDecoder(currentHits);
+                makeClustersGridWindow(currentHits, currentClusters);
+            }
+
+        }
+
+        clustersByModule[modId] = std::move( currentClusters ) ;
+    }
+
+    /*
+     * Third: take the "average" of each cluster
+     */
+    int nTotClu = 0;
+    for (auto& module: clustersByModule) {
+        hitVector connectedHits; // list of ganged hits that are connected to a confirmed ganged hit
+        for (auto& clu: module.second) {
+            // do pattern recognition in the ganged region
+            if ( (clu->hitlist.front())->getIsPixel() && findConnectedGanged(clu, connectedHits) ) // set isSafe
+                clu->isSafe = true;
+        }
+
+        for (auto& clu: module.second) {
+            if ( (clu->hitlist.front())->getIsPixel() && isKilled(clu, connectedHits) ) // set isKilled
+                clu->isKilled = true;
+            averageCluster(clu);
+            nTotClu++; // count all clusters
+        }
+    }
+
+    /*
+     * Fourth: put clusters/hits back in the event hit list
+     */
+    hits.clear();
+
+    int hitCounter=0;
+    int deletedGangedClusters=0;
+    for (auto& module: clustersByModule) {
+        for (const auto& clu: module.second) {
+            // // kill clusters with ganged hits according to ganged pattern recognition
+            if ( m_gangedPatternRecognition && clu->isKilled && !clu->isSafe ) {
+            //     // AA 2009-07-07 removing the "isSafe" protection does not change
+            //     // number of combinations to fit for single muon events
+                deletedGangedClusters++;
+                continue;
+            }
+
+            // store hit by value
+            FTKRawHit cluEquiv = clu->clusterEquiv;
+            hits.push_back(cluEquiv);
+            ++hitCounter;
+        }
+        // delete module.second;
+    }
+
+    /*
+     * Fifth: free memory (could optimize and do this in previous step)
+     */
+    // The atlhit data from event is allocated and destroyed outside this function.
+    // clustersByModuleMap is automatically deleted.
+    clustersByModule.clear();
+}
+
+
+int FTKClusteringEngine::hitIsGanged(const FTKRawHit &hit) {
+    if (FTKSetup::getFTKSetup().getIBLMode()>=1 && hit.getLayer()==0)
+        return 0; // FlagAA: IBL is never ganged
+    if (hit.getIsPixel()) {
+        int phi = hit.getPhiSide();
+        if (pixelRowIsGanged(phi))
+            return phi;
+    }
+    return 0;
+}
+
+
+int FTKClusteringEngine::gangedPartner(const FTKRawHit &hit) {
+    if (hit.getIsPixel()) {
+        switch (hit.getPhiSide()) {
+        case 153:
+            return 160;
+        case 160:
+            return 153;
+        case 155:
+            return 161;
+        case 161:
+            return 155;
+        case 157:
+            return 162;
+        case 162:
+            return 157;
+        case 159:
+            return 163;
+        case 163:
+            return 159;
+        case 168:
+            return 164;
+        case 164:
+            return 168;
+        case 170:
+            return 165;
+        case 165:
+            return 170;
+        case 172:
+            return 166;
+        case 166:
+            return 172;
+        case 174:
+            return 167;
+        case 167:
+            return 174;
+        default:
+            return hit.getPhiSide();
+        }
+    }
+    return -1;
+}
+
+
+bool FTKClusteringEngine::pixelRowIsGanged(const int row)
+{
+    switch (row) {
+    case 153:
+    case 155:
+    case 157:
+    case 159:
+    case 168:
+    case 170:
+    case 172:
+    case 174:
+        return row;        // pixel ganged found (readout channel)
+    }
+    if (160<=row && row<=167)
+        return row;        // pixel ganged found (non readout channel)
+    return false;
+}
+
+
+double FTKClusteringEngine::getDeltaX1A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    float pixXScaleFactor = ftk::clustering::xScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
+    float sensorThickness = ftk::sensorThicknessPixel;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+    }
+    return lround(-(32*32*(30*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch)/2.));
+
+}
+
+
+double FTKClusteringEngine::getDeltaX2A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float pixXScaleFactor = ftk::clustering::xScaleFactorPixel;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+    }
+    return lround(32*(30*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch));
+}
+
+
+int FTKClusteringEngine::getDeltaXEC1A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float pixXScaleFactor = ftk::clustering::xScaleFactorPixel;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+    }
+    return lround(- (32*32*(10*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch)/2.));
+}
+
+
+int FTKClusteringEngine::getDeltaXEC2A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float pixXScaleFactor = ftk::clustering::xScaleFactorPixel;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+    }
+    return lround(32*(10*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch));
+}
+
+
+int FTKClusteringEngine::getDeltaYEC1A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float pixYScaleFactor = ftk::clustering::yScaleFactorPixel;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+        etaPitch = ftk::etaPitchIbl;
+    }
+    return lround(- (32*32*(10*ftk::micrometer*pixYScaleFactor*(sensorThickness/(250*ftk::micrometer))/etaPitch)/2.));
+}
+
+
+int FTKClusteringEngine::getDeltaYEC2A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float pixYScaleFactor = ftk::clustering::yScaleFactorPixel;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;
+        etaPitch = ftk::etaPitchIbl;
+    }
+    return lround(32*(10*ftk::micrometer*pixYScaleFactor*(sensorThickness/(250*ftk::micrometer))/etaPitch));
+}
+
+
+int FTKClusteringEngine::getDeltaY1A(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    int layer = first.getLayer();
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    if (FTKSetup::getFTKSetup().getIBLMode()==0)
+        layer++;
+    float radius = ftk::clustering::radii[layer];
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
+    float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
+    float etaModule = first.getEtaModule()-6;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
+        moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
+        pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 10 to count in unit of 25um
+        etaModule = first.getEtaModule()-8;
+        etaPitch = ftk::etaPitchIbl;
+
+    }
+    return lround ( - 32*32*2* pixYScaleFactor*sensorThickness* etaModule*moduleActiveLength/radius /etaPitch/2. ) + lround( 32*32*2* pixYScaleFactor*sensorThickness*moduleActiveLength/radius /etaPitch/2/2);
+}
+int FTKClusteringEngine::getDeltaY2A(const cluster* clu){
+    FTKRawHit first = *(clu->hitlist.front());
+    int layer = first.getLayer();
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    if (FTKSetup::getFTKSetup().getIBLMode()==0)
+        layer++;
+    float radius = ftk::clustering::radii[layer];
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
+    float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
+    float etaModule = first.getEtaModule()-6;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
+        moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
+        pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 10 to count in unit of 25um
+        etaModule = first.getEtaModule()-8;
+        etaPitch = ftk::etaPitchIbl;
+    }
+    return lround (32*2* pixYScaleFactor*sensorThickness* etaModule*moduleActiveLength/radius /etaPitch) + lround ( - 32*2* pixYScaleFactor*sensorThickness* moduleActiveLength/radius /etaPitch/2.);
+}
+
+int FTKClusteringEngine::getDeltaY1B(const cluster* clu){
+    FTKRawHit first = *(clu->hitlist.front());
+    int layer = first.getLayer();
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    if (FTKSetup::getFTKSetup().getIBLMode()==0)
+        layer++;
+    float radius = ftk::clustering::radii[layer];
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInPixelModule;
+    float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
+        numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInIblModule;
+        moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
+        etaPitch = ftk::etaPitchIbl;
+    }
+    return  lround ( - 32*32* sensorThickness/numberOfEtaPixelsInModule *moduleActiveLength/radius /etaPitch/2);
+}
+
+
+int FTKClusteringEngine::getDeltaY2B(const cluster* clu)
+{
+    FTKRawHit first = *(clu->hitlist.front());
+    int layer = first.getLayer();
+    bool isIBLmodule  = hitOnIBLmodule(first);
+    if (FTKSetup::getFTKSetup().getIBLMode()==0)
+        layer++;
+    float radius = ftk::clustering::radii[layer];
+    float sensorThickness = ftk::sensorThicknessPixel;
+    float etaPitch = ftk::etaPitchPixel;
+    float numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInPixelModule;
+    float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
+    if (isIBLmodule) {
+        sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
+        numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInIblModule;
+        moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
+        etaPitch = ftk::etaPitchIbl;
+    }
+    return lround (32 * sensorThickness/numberOfEtaPixelsInModule *moduleActiveLength/radius/etaPitch ) ;
+}
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringPrintout.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringPrintout.cxx
new file mode 100644
index 000000000000..1eec4cfbda7d
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKClusteringPrintout.cxx
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TrigFTKSim/FTKClusteringPrintout.h"
+#include "TrigFTKSim/FTKClusteringEngine.h"
+#include <iostream>
+#include <iomanip>
+
+/*!
+ * Function printing the hit details
+ * \param hit the hit
+ * \return void
+ */
+void FTKClusteringPrintout::printHit(const FTKRawHit &hit)
+{
+    std::cout << " Hit details: "
+              << " isPixel=" << hit.getIsPixel()
+              << " barrel_ec=" << hit.getBarrelEC()
+              << " layer_disk=" << hit.getLayer()
+              << " phi_module=" << hit.getPhiModule()
+              << " eta_module=" << hit.getEtaModule()
+              << " eta_strip=" << hit.getEtaStrip()
+              << " phi_side=" << hit.getPhiSide()
+              << " tot=" << hit.getTot()
+              << " n_strips=" << hit.getNStrips()
+              << " deltaPhi=" << hit.getDeltaPhi()
+              << " deltaEta=" << hit.getDeltaEta()
+              << " eventindex=" << hit.getEventIndex()
+              << " barcode=" << hit.getBarcode()
+              << " bar_pt=" << hit.getBarcodePt()
+              << " parentage_mask=" << hit.getParentageMask()
+              << "\n";
+}
+
+
+bool FTKClusteringPrintout::clusterSort (const FTK_ClusterCoordHit &i, const FTK_ClusterCoordHit &j)
+{
+    // reverse the hits on the first row if they are above the seed
+    if (i.ccol == 0 && j.ccol == 0 && i.crow <= 10 && j.crow <= 10)
+        return j.crow <= i.crow;
+    else if (i.ccol == j.ccol)
+        return i.crow <= j.crow;
+    else
+        return i.ccol <= j.ccol;
+}
+
+void FTKClusteringPrintout::printCluster(const std::unique_ptr<cluster>&)
+{
+  //To be reimplemented
+}
+
+void FTKClusteringPrintout::printClusterList(clustersByModuleMap clustersByModule)
+{
+    for (auto& module: clustersByModule) { // loop over modules
+        for (auto &cluster: module.second) {
+            printCluster(cluster);
+        }
+    }
+}
+
+
+void FTKClusteringPrintout::printCentroidList(clustersByModuleMap )
+{
+  //To be reimplemented
+}
+
+bool sortWords(const FTKRawHit* i, const FTKRawHit* j)
+{
+    int firstCol  = i->getEtaStrip() + 1;
+    int secondCol = j->getEtaStrip() + 1;
+    int firstRow  = (ftk::clustering::rowsInFEChipPerIblModuleRow - 1) - i->getPhiSide(); //start from 0
+    int secondRow = (ftk::clustering::rowsInFEChipPerIblModuleRow - 1) - j->getPhiSide(); //start from 0
+
+    if(firstCol != secondCol) {
+	return firstCol < secondCol;
+    }
+    else {
+	return firstRow > secondRow;
+    }
+
+
+}
+
+void FTKClusteringPrintout::printHitlist(const hitVector& hitlist)
+{
+    printf("0x08%.7x\n", (hitlist.front()->getIdentifierHash()));
+    for(const auto& hit: hitlist) {
+        printf("0x00%.2x%.2x%.3x", hit->getTot(), hit->getEtaStrip(), hit->getPhiSide());
+        printHit(*(hit.get()));
+    }
+}
+
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKConstantBank.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKConstantBank.cxx
index 74e733fd446c..1800949b6124 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKConstantBank.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKConstantBank.cxx
@@ -13,13 +13,13 @@
 #include <Eigen/Dense>
 #include <iostream>
 #include <iomanip>
+#include <algorithm>
 #include <fstream>
 #include <string>
 #include <cassert>
 #include <cstdio>
 #include <cmath>
 #include <bitset>
-#include <ieee754.h>
 using namespace std;
 
 //#define SIMPLEMJ // ibl undefined simple majority to see if we can get majority for ibl
@@ -291,21 +291,21 @@ void FTKConstantBank::doAuxFW(bool do_it) {
 
 
   // pre-calculate the majority logic elements
-  m_maj_invkk_hw = new signed long long**[m_nsectors];
+  m_maj_invkk_hw = new int**[m_nsectors];
   m_maj_invkk_aux = new signed long long**[m_nsectors];
   m_maj_invkk_pow = new short int**[m_nsectors];
-  m_maj_invkk_pow_hw = new short int**[m_nsectors];
+  m_maj_invkk_pow_hw = new int**[m_nsectors];
   for (int isec=0;isec!=m_nsectors;++isec) { // sector loop
-    m_maj_invkk_hw [isec] = new signed long long*[m_ncoords];
+    m_maj_invkk_hw [isec] = new int*[m_ncoords];
     m_maj_invkk_aux[isec] = new signed long long*[m_ncoords];
     m_maj_invkk_pow[isec] = new short int*[m_ncoords];
-    m_maj_invkk_pow_hw[isec] = new short int*[m_ncoords];
+    m_maj_invkk_pow_hw[isec] = new int*[m_ncoords];
     for (int ix=0;ix!=m_ncoords;++ix) { // 1st coordinate loop    
 
-      m_maj_invkk_hw [isec][ix] = new signed long long[m_ncoords];
+      m_maj_invkk_hw [isec][ix] = new int[m_ncoords];
       m_maj_invkk_aux[isec][ix] = new signed long long[m_ncoords];
       m_maj_invkk_pow[isec][ix] = new short int[m_ncoords];
-      m_maj_invkk_pow_hw[isec][ix] = new short int[m_ncoords];
+      m_maj_invkk_pow_hw[isec][ix] = new int[m_ncoords];
       for (int jx=0;jx!=m_ncoords;++jx) { // 2nd coordinate loop
         m_maj_invkk_hw [isec][ix][jx] = 0;
         m_maj_invkk_aux[isec][ix][jx] = 0;
@@ -323,6 +323,14 @@ void FTKConstantBank::doAuxFW(bool do_it) {
     int npixcy = 6; // we have 6 pixel coords -- not sure what to do about this!!
     /* PIXEL layer [0-5]*/
     bool ofl = false;
+    m_temp = new std::pair<int,int>*[m_ncoords];
+    for (int ix=0;ix!=m_ncoords;++ix) { // 1st coordinate loop
+      m_temp[ix] = new std::pair<int,int>[m_ncoords];
+      for (int jx=0;jx!=m_ncoords;++jx) { // 2nd coordinate loop
+        m_temp[ix][jx].first = 0;
+        m_temp[ix][jx].second = 0;
+      }
+    }
     for (int ix=0;ix!=npixcy;ix+=2) { // pxl layers loop (2 coordinates each)
 
       m_maj_invkk_pow[isec][ix][ix]        = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(m_maj_invkk[isec][ix][ix]    ))) - 1;
@@ -330,35 +338,48 @@ void FTKConstantBank::doAuxFW(bool do_it) {
       m_maj_invkk_pow[isec][ix+1][ix]      = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(m_maj_invkk[isec][ix+1][ix]  ))) - 1;
       m_maj_invkk_pow[isec][ix+1][ix+1]    = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(m_maj_invkk[isec][ix+1][ix+1]))) - 1;
 
-      m_maj_invkk_pow_hw[isec][ix][ix]     = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(8./(const_scale_map[ix]   * const_scale_map[ix]  ) * m_maj_invkk[isec][ix][ix]    ))) - 1;
-      m_maj_invkk_pow_hw[isec][ix][ix+1]   = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(8./(const_scale_map[ix]   * const_scale_map[ix+1]) * m_maj_invkk[isec][ix][ix+1]  ))) - 1;
-      m_maj_invkk_pow_hw[isec][ix+1][ix]   = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(8./(const_scale_map[ix+1] * const_scale_map[ix]  ) * m_maj_invkk[isec][ix+1][ix]  ))) - 1;
-      m_maj_invkk_pow_hw[isec][ix+1][ix+1] = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(8./(const_scale_map[ix+1] * const_scale_map[ix+1]) * m_maj_invkk[isec][ix+1][ix+1]))) - 1;
-
-
       m_maj_invkk_aux[isec][ix][ix]     = aux_asr(m_maj_invkk[isec][ix][ix]     * pow(2, m_maj_invkk_pow[isec][ix][ix]),     0, CONST_PREC, ofl);
       m_maj_invkk_aux[isec][ix][ix+1]   = aux_asr(m_maj_invkk[isec][ix][ix+1]   * pow(2, m_maj_invkk_pow[isec][ix][ix+1]),   0, CONST_PREC, ofl);
       m_maj_invkk_aux[isec][ix+1][ix]   = aux_asr(m_maj_invkk[isec][ix+1][ix]   * pow(2, m_maj_invkk_pow[isec][ix+1][ix]),   0, CONST_PREC, ofl);
       m_maj_invkk_aux[isec][ix+1][ix+1] = aux_asr(m_maj_invkk[isec][ix+1][ix+1] * pow(2, m_maj_invkk_pow[isec][ix+1][ix+1]), 0, CONST_PREC, ofl);
 
-      m_maj_invkk_hw [isec][ix][ix]     = aux_asr(8./(const_scale_map[ix]   * const_scale_map[ix]  ) * m_maj_invkk[isec][ix][ix]     * pow(2, m_maj_invkk_pow_hw[isec][ix][ix]),     0, CONST_PREC, ofl);
-      m_maj_invkk_hw [isec][ix][ix+1]   = aux_asr(8./(const_scale_map[ix]   * const_scale_map[ix+1]) * m_maj_invkk[isec][ix][ix+1]   * pow(2, m_maj_invkk_pow_hw[isec][ix][ix+1]),   0, CONST_PREC, ofl);
-      m_maj_invkk_hw [isec][ix+1][ix]   = aux_asr(8./(const_scale_map[ix+1] * const_scale_map[ix]  ) * m_maj_invkk[isec][ix+1][ix]   * pow(2, m_maj_invkk_pow_hw[isec][ix+1][ix]),   0, CONST_PREC, ofl);
-      m_maj_invkk_hw [isec][ix+1][ix+1] = aux_asr(8./(const_scale_map[ix+1] * const_scale_map[ix+1]) * m_maj_invkk[isec][ix+1][ix+1] * pow(2, m_maj_invkk_pow_hw[isec][ix+1][ix+1]), 0, CONST_PREC, ofl);
+      m_temp[ix][ix] = getFloating(-m_maj_invkk[isec][ix][ix]/(const_scale_map[ix]* const_scale_map[ix] ));
+      m_maj_invkk_hw [isec][ix][ix]     = m_temp[ix][ix].first;
+      m_maj_invkk_pow_hw[isec][ix][ix]  = m_temp[ix][ix].second;
 
+      m_temp[ix][ix+1] = getFloating(-m_maj_invkk[isec][ix][ix+1]/(const_scale_map[ix]* const_scale_map[ix+1] ));
+      m_maj_invkk_hw [isec][ix][ix+1]     = m_temp[ix][ix+1].first;
+      m_maj_invkk_pow_hw[isec][ix][ix+1]  = m_temp[ix][ix+1].second;
+ 
+      m_temp[ix+1][ix] = getFloating(-m_maj_invkk[isec][ix+1][ix]/(const_scale_map[ix+1]* const_scale_map[ix] ));
+      m_maj_invkk_hw [isec][ix+1][ix]     = m_temp[ix+1][ix].first;
+      m_maj_invkk_pow_hw[isec][ix+1][ix]  = m_temp[ix+1][ix].second;
+
+      m_temp[ix+1][ix+1] = getFloating(-m_maj_invkk[isec][ix+1][ix+1]/(const_scale_map[ix+1]* const_scale_map[ix+1] ));
+      m_maj_invkk_hw [isec][ix+1][ix+1]     = m_temp[ix+1][ix+1].first;
+      m_maj_invkk_pow_hw[isec][ix+1][ix+1]  = m_temp[ix+1][ix+1].second;
+     
     } // end pxl layers loop
     /* SCT layers */
     for (int ix=npixcy;ix!=m_ncoords;++ix) { // SCT layers loop (1 coordinate each)
-      m_maj_invkk[isec][ix][ix] = 1./m_maj_kk[isec][ix][ix];      
-
       m_maj_invkk_pow[isec][ix][ix] = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(m_maj_invkk[isec][ix][ix]))) - 1;
       m_maj_invkk_aux[isec][ix][ix] = aux_asr(m_maj_invkk[isec][ix][ix] * pow(2, m_maj_invkk_pow[isec][ix][ix]), 0, CONST_PREC, ofl);
 
-      m_maj_invkk_pow_hw[isec][ix][ix] = CONST_PREC - TMath::CeilNint(TMath::Log2(TMath::Abs(8./(const_scale_map[ix] * const_scale_map[ix]) * m_maj_invkk[isec][ix][ix]))) - 1;
-      m_maj_invkk_hw    [isec][ix][ix] = aux_asr(8./(const_scale_map[ix] * const_scale_map[ix]) * m_maj_invkk[isec][ix][ix] * pow(2, m_maj_invkk_pow_hw[isec][ix][ix]), 0, CONST_PREC, ofl);
+      m_temp[ix][ix] = getFloating(-m_maj_invkk[isec][ix][ix]);///(const_scale_map[ix]* const_scale_map[ix] ));
+      m_maj_invkk_hw [isec][ix][ix]     = m_temp[ix][ix].first;
+      m_maj_invkk_pow_hw[isec][ix][ix]  = m_temp[ix][ix].second;
     } // end SCT layers loop
 
     if (ofl) FTKSetup::PrintMessageFmt(ftk::warn, "  maj/invkk overflowed allowed precision in sector %d.\n", isec);
+    
+    //clean up dynamic memory
+    for (int ix=0;ix!=m_ncoords;++ix) {
+      for (int jx=0;jx!=m_ncoords;++jx) {
+        //delete [] m_temp[ix][jx];
+      }
+      delete [] m_temp[ix];
+    }
+    delete m_temp;
 
   } // end sector loop
 
@@ -438,6 +459,7 @@ int FTKConstantBank::linfit(int secid, FTKTrack &track) const
   if (nmissing!=guess_res) {
     // majority failed, this chi2 is used as a flag
     track.setChi2(0.);
+    track.setChi2FW(0);
   }
   else {
     // evaluate the chi2
@@ -508,6 +530,7 @@ void FTKConstantBank::linfit_chisq(int secid, FTKTrack &trk) const {
     }
 
   trk.setChi2(chi2);
+  trk.setChi2FW(round(chi2));
 }
 
 
@@ -545,15 +568,20 @@ void FTKConstantBank::linfit_pars_eval(int secid, FTKTrack &trk) const
 
   if (m_npars>3) {
     trk.setZ0(pars[3]);
+    trk.setZ0FW(round(pars[3]));
     trk.setZ0Raw(pars[3]);
     trk.setCotTheta(pars[4]);
+    trk.setCTheta(round(pars[4]));
   }
   //cout << "secid: " << secid << endl; // cy debug
   //cout << "phi after corrgen: " << pars[2] << endl; //cy debug
   trk.setHalfInvPt(pars[0]);
+  trk.setInvPtFW(round(pars[0]*1e5)/1e5);
   trk.setIP(pars[1]);
+  trk.setIPFW(round(pars[1]));
   trk.setIPRaw(pars[1]);
   trk.setPhi(pars[2]); // angle is moved within -pi to +pi
+  trk.setPhiFW(round(pars[2])); // angle is moved within -3 to +3
   trk.setPhiRaw(pars[2]); // angle is moved within -pi to +pi
   //    cout << "phi within [-pi,pi]: " << track.getPhi() << endl; // cy debug
 
@@ -647,8 +675,8 @@ int FTKConstantBank::missing_point_guess(FTKTrack &track, int secid, float *newc
       a[0] -= m_maj_kk[secid][col][m_missid[0]]*coords[col];
       a[1] -= m_maj_kk[secid][col][m_missid[1]]*coords[col];
       if (cmDebug > 8) {
-	printf("\ta[0] = %f\n",a[0]);
-	printf("\ta[1] = %f\n",a[1]);
+        FTKSetup::PrintMessageFmt(ftk::info,"\ta[0] = %f\n",a[0]);
+        FTKSetup::PrintMessageFmt(ftk::info,"\ta[1] = %f\n",a[1]);
       }
     }
 
@@ -740,12 +768,12 @@ int FTKConstantBank::missing_point_guess(FTKTrack &track, int secid, float *newc
     }
     if (cmDebug > 5) {
       FTKSetup::PrintMessage(ftk::debg,"new coordinates:\n");
-      if (newcoords)
-	for (int i=0;i<m_ncoords;++i)
-	  printf("\t%d: %f\n",i,newcoords[i]);
-      else
-	for (int i=0;i<m_ncoords;++i)
-	  printf("\t%d: %f\n",i,coords[i]);
+      if (newcoords) {
+        for (int i=0;i<m_ncoords;++i) FTKSetup::PrintMessageFmt(ftk::debg,"\t%d: %f\n",i,newcoords[i]);
+      }  
+      else {
+        for (int i=0;i<m_ncoords;++i) FTKSetup::PrintMessageFmt(ftk::info,"\t%d: %f\n",i,coords[i]);
+      }
       FTKSetup::PrintMessage(ftk::debg,"\n");
     }
 
@@ -757,11 +785,10 @@ int FTKConstantBank::missing_point_guess(FTKTrack &track, int secid, float *newc
 
 unsigned int FTKConstantBank::floatToReg27(float f) {
 
-  ieee754_float f_f;
-  f_f.f = f;
-  int f_sign = f_f.ieee.negative;
-  int f_exp = f_f.ieee.exponent;
-  int f_frac = f_f.ieee.mantissa;
+  int f_f = (*(int*)&f);
+  int f_sign = (f_f >> 31) & 0x1;
+  int f_exp = (f_f >> 23) & 0xFF;
+  int f_frac = f_f & 0x007FFFFF;
   int r_sign;
   int r_exp;
   int r_frac;
@@ -1587,9 +1614,10 @@ signed long long FTKConstantBank::aux_asr(signed long long input , int shift, in
   unsigned long long shifted = abs(input);
 
   // make the baseline shift
-  if (shift > 0) shifted = (shifted << shift);
-  if (shift < 0) {
-    // clear bits that will "go negative"
+  if (shift >= 0) {
+    shifted = (shifted << shift);
+  } else if (shift < 0) {
+    // clear bits that will "go negative"  
     shifted &= ~((static_cast<long long>(1) << -shift) - 1);
     shifted = (shifted >> -shift);
   }
@@ -1599,12 +1627,54 @@ signed long long FTKConstantBank::aux_asr(signed long long input , int shift, in
   if (static_cast<unsigned long long>(llabs(output)) != shifted) overflow = true;
 
   // reinstate the sign.
-  if (input < 0) output *= -1;
+  if (input < 0) {
+    output *= -1;
+    if (shift <= 0){
+      if (abs(input) != shifted * pow(2,-shift)) output -= 1;
+    }
+  }
 
   return output;
 
 }
 
+std::pair<int, int> FTKConstantBank::getFloating(double input)
+{
+  //floating point ranges (assuming 13 bits for significand and 5 bits for exponent)
+  const int minsignificand = -4096;
+  const int maxsignificand = 4095;
+  const int maxexponent = 31;
+ 
+  std::pair<int, int> output;
+
+  //if signficand is greater than 13 bits, return max value
+  if(round(input) > maxsignificand){
+    output.first = maxsignificand;
+    output.second = 0;
+    return output;
+  }
+  if(round(input) < minsignificand){
+    output.first = maxsignificand;
+    output.second = 0;
+    return output;
+  }
+
+  double significand = input;
+  int exponent = 0;
+  while(round(significand*2.0) <= maxsignificand &&
+    round(significand*2.0) >= minsignificand &&
+    exponent <= maxexponent){
+    significand *= 2.0;
+    exponent++;
+  }
+
+  int sig = round(significand);
+
+  output.first = sig;
+  output.second = exponent;
+  return output;
+}
+
 
 void FTKConstantBank::linfit_chisq_aux(int secid, FTKTrack &trk) const {
 
@@ -1613,31 +1683,28 @@ void FTKConstantBank::linfit_chisq_aux(int secid, FTKTrack &trk) const {
   long long chi2HW(0);
 
   bool ofl = false; // overflow
-
+  bool oflhw = false;
+ 
+  for (int i=0;i<m_ncoords;++i) {
+    m_coordsmask[i] = (trk.getBitmask()>>i)&1;
+  }
   // cout << __LINE__ << "::" << __FUNCTION__ << "  sector=" << secid << endl;
 
   for( int i = 0 ; i < m_nconstr ; ++i ) {
 
     long double chi_component = m_kaverage[secid][i];
     signed long long chi_componentLL = aux_asr(m_kaverage_aux[secid][i], 10, 30, ofl); // 30 to the same level as the Sij
-    signed long long chi_componentHW = aux_asr(m_kaverage_aux[secid][i], 10, 30, ofl); 
-    
+    signed long long chi_componentHW = aux_asr(m_kaverage_aux[secid][i], 11, 29, oflhw); //Rui's change to match fw
+
     for( int j = 0 ; j < m_ncoords ; ++j ) {
 
       int p = const_plane_map[j]; int c = const_coord_map[j]; 
 
       chi_component   += m_kernel[secid][i][j]     * trk.getCoord(j); 
       chi_componentLL += m_kernel_aux[secid][i][j] * trk.getAUXCoord(j);
-      chi_componentHW += m_kernel_hw [secid][i][j] * trk.getHwCoord(p, c);
-
-
-
-      // if (i == 0 && !trk.getNMissing() && (j < 6) && (j % 2)) 
-      //   cerr << "JS: " << __FUNCTION__ << "::" << __LINE__ << "   sector=" << secid
-      //                        << "    plane=" << p
-      //                        << "    coord=" << setfill('0') << setw(4) << trk.getHwCoord(p, c)
-      //                        << "    one?=" << setprecision(4) << 8/16.88 * trk.getHwCoord(j/2, 1) / trk.getAUXCoord(j) << endl;
+      if (m_coordsmask[j] == 1) chi_componentHW += aux_asr(m_kernel_hw [secid][i][j] * const_scale_map1[j] * trk.getHwCoord(p, c), -1, 33, oflhw);
 
+      //RZ: Calculate chi_partials without guessed hit first and do the shift, then add the shifted guessed hit component (different from add  then shift)
     }
 
     chi2 += (chi_component * chi_component);
@@ -1645,20 +1712,29 @@ void FTKConstantBank::linfit_chisq_aux(int secid, FTKTrack &trk) const {
     chi_componentLL = aux_asr(chi_componentLL, 0, 30, ofl);
     chi2LL += (chi_componentLL * chi_componentLL);
 
-    chi_componentHW = aux_asr(chi_componentHW, 0, 30, ofl);
-    chi2HW += (chi_componentHW * chi_componentHW);
+    chi_componentHW = aux_asr(chi_componentHW, -2, 27, oflhw); //Rui's change to match fw
+
+    signed long long chi_componentHW_guess=0;
+    if (trk.getNMissing() != 0){ //RZ: calculate chipartial component for guessed hit here
+      for( int j = 0 ; j < m_ncoords ; ++j ) {
+        int p = const_plane_map[j]; int c = const_coord_map[j];
+        if (m_coordsmask[j] == 0) chi_componentHW_guess += aux_asr(m_kernel_hw [secid][i][j] * const_scale_map1[j] * trk.getHwCoord(p, c), 0, 33, oflhw);
+      }
+    }
+    chi_componentHW += aux_asr(chi_componentHW_guess, -3, 27, oflhw); //Rui's change to match fw
 
+    chi2HW += (chi_componentHW * chi_componentHW);
 
   }  
 
   chi2LL = aux_asr(chi2LL, 0, 45, ofl);
-  chi2HW = aux_asr(chi2HW, 0, 45, ofl);
+  chi2HW = aux_asr(chi2HW, 0, 57, oflhw); //Rui's change to match fw
 
   // If there was a bit overflow, set the chi-square to some artificially large value so it fails the cut.
   // Otherwise, set to the caluclated value, scaled back to nominal units.
 
-  float fchi2 = ofl ? 9999999. : chi2HW / pow(2.0, 2.*EFF_SHIFT);
-  trk.setChi2FW(fchi2);
+  float fchi2 = oflhw ? 9999999. : chi2HW / pow(2.0, 2.*13);//EFF_SHIFT); //Rui's change to match fw
+  trk.setChi2FW(round(fchi2));
   trk.setChi2  (fchi2);
 
   // any negative hits?
@@ -1720,10 +1796,10 @@ int FTKConstantBank::missing_point_guess_aux(FTKTrack &track, int secid) const {
   }
 
   // keep track of which hits are missing.
-  int nmissing = 0; int missid[2] = {-1, -1};
+  int nmissing = 0; int m_lmissid[2] = {-1, -1};
   for( int j = 0 ; j < m_ncoords ; ++j ) {
     if (!m_coordsmask[j]) {
-      missid[nmissing] = j;
+      m_lmissid[nmissing] = j;
       nmissing++;
     } 
   }
@@ -1735,28 +1811,27 @@ int FTKConstantBank::missing_point_guess_aux(FTKTrack &track, int secid) const {
     return 0;
   }
   if (nmissing == 2) { // 2 missing, must be consecutive pixel hits.
-    if (missid[0] >= npixcy || missid[0]+1 != missid[1]) {
-      // FTKSetup::PrintMessageFmt(ftk::warn, "Two guessed coordinates must be from the same pix hit: missing %d, %d.\n", missid[0], missid[1]);
+    if (m_lmissid[0] >= npixcy || m_lmissid[0]+1 != m_lmissid[1]) {
+      // FTKSetup::PrintMessageFmt(ftk::warn, "Two guessed coordinates must be from the same pix hit: missing %d, %d.\n", m_missid[0], m_missid[1]);
       return 0;
     }
   }
   if (nmissing == 1) { // can't imagine how this would happen...
-    if (missid[0] < npixcy) {
+    if (m_lmissid[0] < npixcy) {
       // FTKSetup::PrintMessage(ftk::warn, "Single miss/drop must be in SCT - returning.\n");
       return 0;
     }
   }
 
-
   // calculate the chi partials
   // long double* m_partials = new long double [m_ncoords];
-  long long*   partialsLL = new long long [m_ncoords];
-  long long*   partialsHW = new long long [m_ncoords];
+  long long*   m_partialsLL = new long long [m_ncoords];
+  long long*   m_partialsHW = new long long [m_ncoords];
   for (int i = 0; i < m_nconstr; ++i) {
 
     // m_partials[i]   = m_kaverage[secid][i]; 
-    partialsLL[i] = aux_asr(m_kaverage_aux[secid][i], 10, 30, ofl); // 30
-    partialsHW[i] = aux_asr(m_kaverage_aux[secid][i], 10, 30, ofl); // 30
+    m_partialsLL[i] = aux_asr(m_kaverage_aux[secid][i], 10, 30, ofl); // 30
+    m_partialsHW[i] = aux_asr(m_kaverage_aux[secid][i], 11, 30, ofl); //9
 
     for (int j = 0 ; j < m_ncoords ; ++j ) {
       if (m_coordsmask[j]) {
@@ -1764,16 +1839,17 @@ int FTKConstantBank::missing_point_guess_aux(FTKTrack &track, int secid) const {
         int p = const_plane_map[j]; int c = const_coord_map[j]; 
 
         // m_partials[i]   += m_kernel[secid][i][j] * track.getCoord(j);
-        partialsLL[i] += m_kernel_aux[secid][i][j] * track.getAUXCoord(j); 
-        partialsHW[i] += m_kernel_hw[secid][i][j]  * track.getHwCoord(p, c); 
+        m_partialsLL[i] += m_kernel_aux[secid][i][j] * track.getAUXCoord(j); 
+        m_partialsHW[i] += aux_asr(m_kernel_hw[secid][i][j]  * const_scale_map1[j] * track.getHwCoord(p, c), -1, 33, ofl); //Rui's change to match fw
       }
     }
+    m_partialsHW[i] = aux_asr(m_partialsHW[i], -2, 27, ofl); //Rui's change to match fw
   }  
 
   if (ofl) {
     FTKSetup::PrintMessage(ftk::warn, "AUX-style partials calculation had an overflow!!!\n");
-    delete [] partialsLL;
-    delete [] partialsHW;
+    delete [] m_partialsLL;
+    delete [] m_partialsHW;
     return 0; 
   }
 
@@ -1783,18 +1859,17 @@ int FTKConstantBank::missing_point_guess_aux(FTKTrack &track, int secid) const {
   long long tHW[2] = {0, 0};
   for (int j = 0; j < nmissing; ++j) {
     for (int i = 0; i < m_nconstr; ++i ) {
-      // t[j] -= m_kernel[secid][i][missid[j]] * m_partials[i];
-      tLL[j] -= m_kernel_aux[secid][i][missid[j]] * partialsLL[i];
-      tHW[j] -= m_kernel_hw[secid][i][missid[j]]  * partialsHW[i];
+      tLL[j] -= m_kernel_aux[secid][i][m_lmissid[j]] * m_partialsLL[i];
+      tHW[j] += m_kernel_hw[secid][i][m_lmissid[j]]  * m_partialsHW[i]; 
     }
 
     tLL[j] = aux_asr(tLL[j], 0, 50, ofl); // 50
-    tHW[j] = aux_asr(tHW[j], 0, 50, ofl); // 50
-    // cerr << "JS: " << j << " ofl=" << ofl << "  tHW[j]/tLL[j]=" << (1./const_scale_map[missid[j]])*tHW[j]/tLL[j] << endl;
+    tHW[j] = aux_asr(tHW[j], -16, 27, ofl); //Rui's change to match fw
   }
+
   // delete [] m_partials;
-  delete [] partialsLL;
-  delete [] partialsHW;
+  delete [] m_partialsLL;
+  delete [] m_partialsHW;
 
   if (ofl) FTKSetup::PrintMessage(ftk::warn, "AUX-style t-vector calculation had an overflow!!!\n");
 
@@ -1804,7 +1879,7 @@ int FTKConstantBank::missing_point_guess_aux(FTKTrack &track, int secid) const {
   // for (int ix = 0; ix < nmissing; ++ix) // 1st coordinate loop    
   //   for (int jx=0; jx < nmissing; ++jx) // 2nd coordinate loop
   //     for (int row=0;row!=m_nconstr;++row) 
-  //       coef[ix][jx] += m_kernel[secid][row][missid[ix]] * m_kernel[secid][row][missid[jx]];
+  //       coef[ix][jx] += m_kernel[secid][row][m_missid[ix]] * m_kernel[secid][row][m_missid[jx]];
   // coef.Invert();
   // TVectorD newcoord = coef * t;
   // fstream outfs;
@@ -1812,89 +1887,62 @@ int FTKConstantBank::missing_point_guess_aux(FTKTrack &track, int secid) const {
 
 
   // get the pointer to the track coordinates
+  int cHW_signed[2] = {0, 0};
   unsigned int cHW[2] = {0, 0};
+
   float *coords = track.getCoords();
   if (nmissing == 1) {
-
-    coords[missid[0]] = tLL[0] * m_maj_invkk_aux[secid][missid[0]][missid[0]]
-                          / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][missid[0]][missid[0]] - 1);
-
-    cHW[0] = tHW[0] * m_maj_invkk_hw[secid][missid[0]][missid[0]]
-             / pow(2., EFF_SHIFT_HW + KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[0]][missid[0]] - 1);
+    coords[m_lmissid[0]] = tLL[0] * m_maj_invkk_aux[secid][m_lmissid[0]][m_lmissid[0]]
+      / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][m_lmissid[0]][m_lmissid[0]] - 1);
+    cHW_signed[0] = aux_asr(tHW[0] * m_maj_invkk_hw[secid][m_lmissid[0]][m_lmissid[0]],-( 5 + m_maj_invkk_pow_hw[secid][m_lmissid[0]][m_lmissid[0]]), 40, ofl); //Rui's change to match fw
+    cHW[0] = max(cHW_signed[0],0); //RZ: if guessed hit < 0, set it to 0
 
     FTKHit newhit(1);
-    newhit.setHwCoord(0, cHW[0]);
-    track.setFTKHit(const_plane_map[missid[0]], newhit);
-
-
-    ///  cout << __LINE__ << "  JS: pow  aux=" << m_maj_invkk_pow[secid][missid[0]][missid[0]] << "   hw=" << m_maj_invkk_pow_hw[secid][missid[0]][missid[0]] << endl;
-    ///  cout << __LINE__ << "  JS: aux=" << tLL[0] * m_maj_invkk_aux[secid][missid[0]][missid[0]] 
-    ///                                      / pow(2., KERN_SHIFT + m_maj_invkk_pow[secid][missid[0]][missid[0]] - 1) 
-    ///                   << "      hw="  << tHW[0] * m_maj_invkk_hw[secid][missid[0]][missid[0]] 
-    ///                                      / pow(2., KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[0]][missid[0]] - 1) << endl;
-
-    ///  cout << __LINE__ << "  JS:  " << missid[0] << "    C=" << track.getCoord(missid[0]) 
-    ///                                               << "    A=" << 1.*track.getAUXCoord(missid[0]) / const_scale_map[missid[0]]
-    ///                                               << "    H=" << track.getHwCoord(const_plane_map[missid[0]], 0) << endl;
-    ///  cout << __LINE__ << "  JS:  " << missid[0] << "  A/C=" << 0.125 * track.getAUXCoord(const_plane_map[missid[0]])   / track.getCoord(missid[0]) 
-    ///                                               << "  H/C=" << 1. * track.getHwCoord(const_plane_map[missid[0]], 0) / track.getCoord(missid[0])
-    ///                                               << "  H/A=" << 1. * track.getHwCoord(const_plane_map[missid[0]], 0) * const_scale_map[missid[0]] / track.getAUXCoord(missid[0]) 
-    ///                                               << "  set/ret=" << 1. * cHW[0] / track.getHwCoord(const_plane_map[missid[0]], 0) << endl;
-
+    cHW[0] = aux_asr(cHW[0], -3, 27, ofl); //Rui's change to match fw
 
+    newhit.setHwCoord(0, cHW[0]);
+    track.setFTKHit(const_plane_map[m_lmissid[0]], newhit);
 
   } else if (nmissing == 2) {
+    coords[m_lmissid[0]] =   tLL[0] * m_maj_invkk_aux[secid][m_lmissid[0]][m_lmissid[0]]
+                           / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][m_lmissid[0]][m_lmissid[0]] - 1)
+                         + tLL[1] * m_maj_invkk_aux[secid][m_lmissid[0]][m_lmissid[1]]
+                           / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][m_lmissid[0]][m_lmissid[1]] - 1);
+    coords[m_lmissid[1]] =   tLL[0] * m_maj_invkk_aux[secid][m_lmissid[1]][m_lmissid[0]]
+                           / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][m_lmissid[1]][m_lmissid[0]] - 1)
+                         + tLL[1] * m_maj_invkk_aux[secid][m_lmissid[1]][m_lmissid[1]]
+                           / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][m_lmissid[1]][m_lmissid[1]] - 1);
 
-    coords[missid[0]] =   tLL[0] * m_maj_invkk_aux[secid][missid[0]][missid[0]]
-                            / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][missid[0]][missid[0]])
-                          + tLL[1] * m_maj_invkk_aux[secid][missid[0]][missid[1]]
-                            / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][missid[0]][missid[1]]);
-
-    coords[missid[1]] =   tLL[0] * m_maj_invkk_aux[secid][missid[1]][missid[0]]
-                            / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][missid[1]][missid[0]])
-                          + tLL[1] * m_maj_invkk_aux[secid][missid[1]][missid[1]]
-                            / pow(2., EFF_SHIFT + KERN_SHIFT + m_maj_invkk_pow[secid][missid[1]][missid[1]]);
-
-
-    cHW[0] =   tHW[0] * m_maj_invkk_hw[secid][missid[0]][missid[0]]
-                / pow(2., EFF_SHIFT_HW + KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[0]][missid[0]])
-             + tHW[1] * m_maj_invkk_hw[secid][missid[0]][missid[1]]
-                / pow(2., EFF_SHIFT_HW + KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[0]][missid[1]]);
+    cHW_signed[0] =  aux_asr(tHW[0] * m_maj_invkk_hw[secid][m_lmissid[0]][m_lmissid[0]], -(5+m_maj_invkk_pow_hw[secid][m_lmissid[0]][m_lmissid[0]]), 40,ofl)+ aux_asr(tHW[1] * m_maj_invkk_hw[secid][m_lmissid[0]][m_lmissid[1]], -(5+m_maj_invkk_pow_hw[secid][m_lmissid[0]][m_lmissid[1]]), 40, ofl); //Rui's change to match fw
+    cHW_signed[1] =  aux_asr(tHW[0] * m_maj_invkk_hw[secid][m_lmissid[1]][m_lmissid[0]], -(5+m_maj_invkk_pow_hw[secid][m_lmissid[1]][m_lmissid[0]]), 40, ofl)+aux_asr(tHW[1] * m_maj_invkk_hw[secid][m_lmissid[1]][m_lmissid[1]], -(5+m_maj_invkk_pow_hw[secid][m_lmissid[1]][m_lmissid[1]]), 40, ofl); //Rui's change to match fw
 
-    cHW[1] =   tHW[0] * m_maj_invkk_hw[secid][missid[1]][missid[0]]
-                / pow(2., EFF_SHIFT_HW + KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[1]][missid[0]])
-             + tHW[1] * m_maj_invkk_hw[secid][missid[1]][missid[1]]
-                / pow(2., EFF_SHIFT_HW + KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[1]][missid[1]]);
+    cHW[0] = max(cHW_signed[0],0);
+    cHW[1] = max(cHW_signed[1],0);
 
     FTKHit newhit(2);
+    cHW[0] = aux_asr(cHW[0], -1, 27, ofl); //Rui's change to match fw
+    cHW[1] = aux_asr(cHW[1], 0, 27, ofl); //Rui's change to match fw
+
     newhit.setHwCoord(0, cHW[0]);
     newhit.setHwCoord(1, cHW[1]);
-    track.setFTKHit(const_plane_map[missid[0]], newhit);
-
-
-    ////  cout << __LINE__ << "  JS: pow  aux=" << m_maj_invkk_pow[secid][missid[0]][missid[0]] << "   hw=" << m_maj_invkk_pow_hw[secid][missid[0]][missid[0]] << endl;
-    ////  cout << __LINE__ << "  JS: aux=" << tLL[0] * m_maj_invkk_aux[secid][missid[0]][missid[0]] 
-    ////                                      / pow(2., KERN_SHIFT + m_maj_invkk_pow[secid][missid[0]][missid[0]] - 1) 
-    ////                   << "      hw="  << tHW[0] * m_maj_invkk_hw[secid][missid[0]][missid[0]] 
-    ////                                      / pow(2., KERN_SHIFT_HW + m_maj_invkk_pow_hw[secid][missid[0]][missid[0]] - 1) << endl;
-
-
-    ////  cout << __LINE__ << "  JS:  " << missid[0] << "   C=" << track.getCoord(missid[0]) 
-    ////                                               << "   A=" << track.getAUXCoord(missid[0]) 
-    ////                                               << "   H=" << track.getHwCoord(const_plane_map[missid[0]], 0) << endl;
-    ////  cout << __LINE__ << "  JS:  " << missid[0] << " A/C=" << 1. * track.getAUXCoord(const_plane_map[missid[0]])   / track.getCoord(missid[0]) 
-    ////                                               << " H/C=" << 1. * track.getHwCoord(const_plane_map[missid[0]], 0) / track.getCoord(missid[0])
-    ////                                               << " H/A=" << 1. * track.getHwCoord(const_plane_map[missid[0]], 0) * const_scale_map[missid[0]] / track.getAUXCoord(missid[0]) 
-    ////                                               << "  set/ret=" << 1. * cHW[0] / track.getHwCoord(const_plane_map[missid[0]], 0) << endl;
-
-
-    ////  cout << __LINE__ << "  JS:  " << missid[1] << "   C=" << track.getCoord(missid[1]) 
-    ////                                               << "   A=" << track.getAUXCoord(missid[1]) 
-    ////                                               << "   H=" << track.getHwCoord(const_plane_map[missid[1]], 1) << endl;
-    ////  cout << __LINE__ << "  JS:  " << missid[1] << " A/C=" << 1. * track.getAUXCoord(const_plane_map[missid[1]])   / track.getCoord(missid[1]) 
-    ////                                               << " H/C=" << 1. * track.getHwCoord(const_plane_map[missid[1]], 1) / track.getCoord(missid[1]) 
-    ////                                               << " H/A=" << 1. * track.getHwCoord(const_plane_map[missid[1]], 1) * const_scale_map[missid[1]] / track.getAUXCoord(missid[1])
-    ////                                               << "  set/ret=" << 1. * cHW[1] / track.getHwCoord(const_plane_map[missid[1]], 1) << endl;
+    track.setFTKHit(const_plane_map[m_lmissid[0]], newhit);
+
+    ////  cout << __LINE__ << "  JS:  " << m_missid[0] << "   C=" << track.getCoord(m_missid[0]) 
+    ////                                               << "   A=" << track.getAUXCoord(m_missid[0]) 
+    ////                                               << "   H=" << track.getHwCoord(const_plane_map[m_missid[0]], 0) << endl;
+    ////  cout << __LINE__ << "  JS:  " << m_missid[0] << " A/C=" << 1. * track.getAUXCoord(const_plane_map[m_missid[0]])   / track.getCoord(m_missid[0]) 
+    ////                                               << " H/C=" << 1. * track.getHwCoord(const_plane_map[m_missid[0]], 0) / track.getCoord(m_missid[0])
+    ////                                               << " H/A=" << 1. * track.getHwCoord(const_plane_map[m_missid[0]], 0) * const_scale_map[m_missid[0]] / track.getAUXCoord(m_missid[0]) 
+    ////                                               << "  set/ret=" << 1. * cHW[0] / track.getHwCoord(const_plane_map[m_missid[0]], 0) << endl;
+
+
+    ////  cout << __LINE__ << "  JS:  " << m_missid[1] << "   C=" << track.getCoord(m_missid[1]) 
+    ////                                               << "   A=" << track.getAUXCoord(m_missid[1]) 
+    ////                                               << "   H=" << track.getHwCoord(const_plane_map[m_missid[1]], 1) << endl;
+    ////  cout << __LINE__ << "  JS:  " << m_missid[1] << " A/C=" << 1. * track.getAUXCoord(const_plane_map[m_missid[1]])   / track.getCoord(m_missid[1]) 
+    ////                                               << " H/C=" << 1. * track.getHwCoord(const_plane_map[m_missid[1]], 1) / track.getCoord(m_missid[1]) 
+    ////                                               << " H/A=" << 1. * track.getHwCoord(const_plane_map[m_missid[1]], 1) * const_scale_map[m_missid[1]] / track.getAUXCoord(m_missid[1])
+    ////                                               << "  set/ret=" << 1. * cHW[1] / track.getHwCoord(const_plane_map[m_missid[1]], 1) << endl;
 
   } 
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKDataInput.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKDataInput.cxx
index 4774973c9e53..ca597fe351ba 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKDataInput.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKDataInput.cxx
@@ -6,7 +6,7 @@
 #include "TrigFTKSim/FTKRawHit.h"
 #include "TrigFTKSim/FTKSetup.h"
 #include "TrigFTKSim/FTKSplitEncoder.h"
-#include "TrigFTKSim/atlClustering.h"
+#include "TrigFTKSim/FTKClusteringEngine.h"
 #include "xAODTracking/TrackParticleContainer.h"
 
 #include <fstream>
@@ -14,36 +14,36 @@
 using namespace std;
 
 FTKDataInput::FTKDataInput() :
-  m_nevent(-1), m_pmap(0x0), m_pmap_unused(0x0),
-  m_reghits(0x0), m_run_number(0ul), m_event_number(0ul) ,
-  m_original_reghits(0), m_nplanes(0), m_nregions(0), m_nsubregions(0),
-  m_ncoords(0), m_region(-1), m_subregion(-1), 
-  m_Clustering(true), m_SaveClusterContent(false),
-  m_DiagClustering(true), m_SctClustering(false), m_PixelClusteringMode(0), m_Ibl3DRealistic(false), m_DuplicateGanged(true),
-  m_GangedPatternRecognition(false),
-  m_SplitBlayerModules(false),  
-  m_init(false), m_save_unused(false), m_read_clusters(false),
-  m_trackinput(0), m_roadinput(0), // cy road
-  m_nao_nhits_tot(0), m_nao_nclus_tot(0), m_firstEventFTK(-1),
-  m_goodRegions(0),
-  m_regional(false)
+    m_nevent(-1), m_pmap(0x0), m_pmap_unused(0x0),
+    m_reghits(0x0), m_run_number(0ul), m_event_number(0ul) ,
+    m_original_reghits(0), m_nplanes(0), m_nregions(0), m_nsubregions(0),
+    m_ncoords(0), m_region(-1), m_subregion(-1),
+    m_Clustering(true), m_SaveClusterContent(false),
+    m_DiagClustering(true), m_SctClustering(false), m_PixelClusteringMode(0), m_Ibl3DRealistic(false), m_DuplicateGanged(true),
+    m_GangedPatternRecognition(false),
+    m_SplitBlayerModules(false),
+    m_init(false), m_save_unused(false), m_read_clusters(false),
+    m_trackinput(0), m_roadinput(0), // cy road
+    m_nao_nhits_tot(0), m_nao_nclus_tot(0), m_firstEventFTK(-1),
+    m_goodRegions(0),
+    m_regional(false)
 {;}
 
 FTKDataInput::FTKDataInput(const FTKPlaneMap *pmap, const FTKPlaneMap *pmap_unused) :
-  m_nevent(-1), m_pmap(pmap), m_pmap_unused(pmap_unused),
-  m_reghits(0x0), m_run_number(0ul), m_event_number(0ul) ,
-  m_original_reghits(0),
-  m_nplanes(m_pmap->getNPlanes()), m_nregions(0), m_nsubregions(0),
-  m_ncoords(0), m_region(-1), m_subregion(-1), 
-  m_Clustering(true), m_SaveClusterContent(false),
-  m_DiagClustering(true), m_SctClustering(false), m_PixelClusteringMode(0), m_Ibl3DRealistic(false), m_DuplicateGanged(true),
-  m_GangedPatternRecognition(false),
-  m_SplitBlayerModules(false),  
-  m_init(false), m_save_unused(false), m_read_clusters(false),
-  m_trackinput(0), m_roadinput(0), // cy road
-  m_nao_nhits_tot(0), m_nao_nclus_tot(0), m_firstEventFTK(-1),
-  m_goodRegions(0),
-  m_regional(false)
+    m_nevent(-1), m_pmap(pmap), m_pmap_unused(pmap_unused),
+    m_reghits(0x0), m_run_number(0ul), m_event_number(0ul) ,
+    m_original_reghits(0),
+    m_nplanes(m_pmap->getNPlanes()), m_nregions(0), m_nsubregions(0),
+    m_ncoords(0), m_region(-1), m_subregion(-1),
+    m_Clustering(true), m_SaveClusterContent(false),
+    m_DiagClustering(true), m_SctClustering(false), m_PixelClusteringMode(0), m_Ibl3DRealistic(false), m_DuplicateGanged(true),
+    m_GangedPatternRecognition(false),
+    m_SplitBlayerModules(false),
+    m_init(false), m_save_unused(false), m_read_clusters(false),
+    m_trackinput(0), m_roadinput(0), // cy road
+    m_nao_nhits_tot(0), m_nao_nclus_tot(0), m_firstEventFTK(-1),
+    m_goodRegions(0),
+    m_regional(false)
 {;}
 
 FTKDataInput::~FTKDataInput()
@@ -54,274 +54,273 @@ FTKDataInput::~FTKDataInput()
     value is accepted */
 void FTKDataInput::setPlaneMaps(const FTKPlaneMap *pmap, const FTKPlaneMap *pmap_unused)
 {
-  m_pmap = pmap;
-  m_nplanes = pmap->getNPlanes();
-  m_pmap_unused = pmap_unused;
+    m_pmap = pmap;
+    m_nplanes = pmap->getNPlanes();
+    m_pmap_unused = pmap_unused;
 }
 
 
 /** initilize clustering settings (bad: using global variables!) */
-void FTKDataInput::initClustering() 
+void FTKDataInput::initClustering()
 {
-  SAVE_CLUSTER_CONTENT = m_SaveClusterContent;
-  DIAG_CLUSTERING = m_DiagClustering;
-  SCT_CLUSTERING = m_SctClustering;
-  PIXEL_CLUSTERING_MODE = m_PixelClusteringMode;
-  IBL3D_REALISTIC = m_Ibl3DRealistic;
-  DUPLICATE_GANGED = m_DuplicateGanged;
-  GANGED_PATTERN_RECOGNITION = m_GangedPatternRecognition;
-  SPLIT_BLAYER_MODULES = m_SplitBlayerModules;
-  //
-  //  new clustering class and pass options
+    //  new clustering class and pass options
+     m_clusteringEngine = new FTKClusteringEngine(m_SaveClusterContent,
+                                         m_DiagClustering,
+                                         m_SctClustering,
+                                         m_Ibl3DRealistic,
+                                         m_DuplicateGanged,
+                                         m_GangedPatternRecognition,
+                                         m_SplitBlayerModules,
+                                         m_PixelClusteringMode);
 
 }
 
 /** Process the event:cluster raw hits and convert them to FTKHits */
 void FTKDataInput::processEvent(bool clearOrig)
 {
-  // reset statistics
-  m_nao_nhits_tot=0;
-  m_nao_nclus_tot=0;
-
-  // reset hit list
-  m_hits.clear();
-  m_hits_unused.clear();
-
-  if (m_regional) {
-    // process only the important regions and exit
-    for (int ireg=0;ireg!=m_nregions;++ireg) {
-      if (m_goodRegions[ireg]) processRegion(ireg, clearOrig);
+    // reset statistics
+    m_nao_nhits_tot=0;
+    m_nao_nclus_tot=0;
+
+    // reset hit list
+    m_hits.clear();
+    m_hits_unused.clear();
+
+    if (m_regional) {
+        // process only the important regions and exit
+        for (int ireg=0;ireg!=m_nregions;++ireg) {
+            if (m_goodRegions[ireg]) processRegion(ireg, clearOrig);
+        }
+
+        // exit
+        return;
     }
 
-    // exit
-    return;
-  }
 
-
-  if(FTKSetup::getDBG()) {
-    cout << "DBG: Original hits = " << m_original_hits.size() << endl;
-  }
-  m_nao_nhits_tot = m_original_hits.size();
-
-  if (!m_read_clusters) {
-      // if raw channels are read the clustering algorithm can be applyied (default)
-    if (m_Clustering ) {
-      atlClusteringLNF(m_original_hits);
-      atlClusteringBlayer(m_original_hits);  // split blayer modules in half, if requested
-    }
-    else {
-      // If the clustering it is not executed the FTKRawHit.m_truth field has to be fixed
-      vector<FTKRawHit>::iterator ihit = m_original_hits.begin();
-      vector<FTKRawHit>::const_iterator ihit_end = m_original_hits.end();
-      for (;ihit!=ihit_end;++ihit) { // loop over the raw hits
-	FTKRawHit &curhit = *ihit;
-	MultiTruth mt;
-	MultiTruth::Barcode uniquecode(curhit.getEventIndex(),curhit.getBarcode());
-	mt.maximize(uniquecode,curhit.getBarcodePt());
-	curhit.setTruth(mt);
-      } // end hit
-    }
-  }
-
-  if(FTKSetup::getDBG()) {
-    cout << "DBG: Clustered hits = " << m_original_hits.size() << endl;
-  }
-  m_nao_nclus_tot = m_original_hits.size();
-
-  // read SCTtrk values (Constantinos case) and push SCTtrk hits into hits vector:
-  // Note that it assumes the raw data input and root track input are fully in sync!
-  if(m_trackinput && m_roadinput) {
-    for(int i=0;i<m_nregions;i++) {
-      // for now, only read tracks from "current" region
-      if (i!=m_region) continue;
-      int res = m_trackinput[i]->nextEvent();
-      if(res<0) {
-	FTKSetup::PrintMessage(ftk::sevr,"SCTtrk input ran out before hit input");
-      }
-      res = m_roadinput[i]->nextEvent();
-      if(res<0) {
-	FTKSetup::PrintMessage(ftk::sevr,"SCTtrk road input ran out before hit input");
-      }
-      const FTKTrack *cur_track = m_trackinput[i]->nextTrack(m_region);
-      while (cur_track) {
-	FTKRawHit tmphit(cur_track,m_pmap->getSCTtrkPlane());
-	m_original_hits.push_back(tmphit);
-	cur_track = m_trackinput[i]->nextTrack(m_region);
-      }
-    }
-  }
-
-  // filter the hit end convert input hit format into FTKHit
-  vector<FTKRawHit>::iterator irawhit = m_original_hits.begin();
-  FTKSetup &ftkset = FTKSetup::getFTKSetup();
-  
-  // create one list for each plane to order the hits
-  list<FTKHit> *planelist = new list<FTKHit>[m_nplanes];
-
-  for (;irawhit!=m_original_hits.end();++irawhit) { // loop over clusters
-    FTKRawHit &rawhit = *irawhit;
-
-    // check if end-cap hits should be accepted
-    if (rawhit.getBarrelEC()!=0 && ftkset.getBarrelOnly() == true) {
-      // skip this hit
-      continue;
-    }
-    // check if SCT hits should be accepted
-    if(rawhit.getIsSCT() && ftkset.getSCTtrkMode()) {
-      // skip this hit
-      continue;
-    }
-    if (m_pmap->getMap(rawhit.getHitType(),rawhit.getBarrelEC()!=0,rawhit.getLayer()).getPlane() != -1) {
-      // accept this hit
-      FTKHit tmphit = rawhit.getFTKHit(m_pmap);
-      assert(rawhit.getTruth());
-      tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
-      planelist[tmphit.getPlane()].push_front(tmphit);
+    if(FTKSetup::getDBG()) {
+        cout << "DBG: Original hits = " << m_original_hits.size() << endl;
     }
-    else if (m_save_unused) {
-      // accept this hit
-      FTKHit tmphit = rawhit.getFTKHit(m_pmap_unused);
-      assert(rawhit.getTruth());
-      tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
-      m_hits_unused.push_back(tmphit);
+    m_nao_nhits_tot = m_original_hits.size();
+
+    if (!m_read_clusters) {
+        // if raw channels are read the clustering algorithm can be applyied (default)
+        if (m_Clustering ) {
+            m_clusteringEngine->atlClusteringLNF(m_original_hits);
+            m_clusteringEngine->atlClusteringBlayer(m_original_hits);  // split blayer modules in half, if requested
+        }
+        else {
+            // If the clustering it is not executed the FTKRawHit.m_truth field has to be fixed
+            vector<FTKRawHit>::iterator ihit = m_original_hits.begin();
+            vector<FTKRawHit>::const_iterator ihit_end = m_original_hits.end();
+            for (;ihit!=ihit_end;++ihit) { // loop over the raw hits
+                FTKRawHit &curhit = *ihit;
+                MultiTruth mt;
+                MultiTruth::Barcode uniquecode(curhit.getEventIndex(),curhit.getBarcode());
+                mt.maximize(uniquecode,curhit.getBarcodePt());
+                curhit.setTruth(mt);
+            } // end hit
+        }
     }
-  } // end loop over clusters
 
-  for (int ipl=0;ipl<m_nplanes;++ipl) { // loop over the planes
-    list<FTKHit>::iterator tmphit = planelist[ipl].begin();
-    for (;tmphit!=planelist[ipl].end();++tmphit) {
-      m_hits.push_back(*tmphit);
+    if(FTKSetup::getDBG()) {
+        cout << "DBG: Clustered hits = " << m_original_hits.size() << endl;
+    }
+    m_nao_nclus_tot = m_original_hits.size();
+
+    // read SCTtrk values (Constantinos case) and push SCTtrk hits into hits vector:
+    // Note that it assumes the raw data input and root track input are fully in sync!
+    if(m_trackinput && m_roadinput) {
+        for(int i=0;i<m_nregions;i++) {
+            // for now, only read tracks from "current" region
+            if (i!=m_region) continue;
+            int res = m_trackinput[i]->nextEvent();
+            if(res<0) {
+                FTKSetup::PrintMessage(ftk::sevr,"SCTtrk input ran out before hit input");
+            }
+            res = m_roadinput[i]->nextEvent();
+            if(res<0) {
+                FTKSetup::PrintMessage(ftk::sevr,"SCTtrk road input ran out before hit input");
+            }
+            const FTKTrack *cur_track = m_trackinput[i]->nextTrack(m_region);
+            while (cur_track) {
+                FTKRawHit tmphit(cur_track,m_pmap->getSCTtrkPlane());
+                m_original_hits.push_back(tmphit);
+                cur_track = m_trackinput[i]->nextTrack(m_region);
+            }
+        }
     }
-  } // end loop over the planes
-
-  // clear raw hits since we don't need them anymore
-  if(clearOrig)
-    m_original_hits.clear();
 
-  delete [] planelist;
+    // filter the hit end convert input hit format into FTKHit
+    vector<FTKRawHit>::iterator irawhit = m_original_hits.begin();
+    FTKSetup &ftkset = FTKSetup::getFTKSetup();
+
+    // create one list for each plane to order the hits
+    list<FTKHit> *planelist = new list<FTKHit>[m_nplanes];
+
+    for (;irawhit!=m_original_hits.end();++irawhit) { // loop over clusters
+        FTKRawHit &rawhit = *irawhit;
+
+        // check if end-cap hits should be accepted
+        if (rawhit.getBarrelEC()!=0 && ftkset.getBarrelOnly() == true) {
+            // skip this hit
+            continue;
+        }
+        // check if SCT hits should be accepted
+        if(rawhit.getIsSCT() && ftkset.getSCTtrkMode()) {
+            // skip this hit
+            continue;
+        }
+        if (m_pmap->getMap(rawhit.getHitType(),rawhit.getBarrelEC()!=0,rawhit.getLayer()).getPlane() != -1) {
+            // accept this hit
+            FTKHit tmphit = rawhit.getFTKHit(m_pmap);
+            assert(rawhit.getTruth());
+            tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
+            planelist[tmphit.getPlane()].push_front(tmphit);
+        }
+        else if (m_save_unused) {
+            // accept this hit
+            FTKHit tmphit = rawhit.getFTKHit(m_pmap_unused);
+            assert(rawhit.getTruth());
+            tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
+            m_hits_unused.push_back(tmphit);
+        }
+    } // end loop over clusters
+
+    for (int ipl=0;ipl<m_nplanes;++ipl) { // loop over the planes
+        list<FTKHit>::iterator tmphit = planelist[ipl].begin();
+        for (;tmphit!=planelist[ipl].end();++tmphit) {
+            m_hits.push_back(*tmphit);
+        }
+    } // end loop over the planes
+
+    // clear raw hits since we don't need them anymore
+    if(clearOrig)
+        m_original_hits.clear();
+
+    delete [] planelist;
 }
 
 
 void FTKDataInput::processRegion(int curreg, bool clearOrig)
 {
-  
-  if (m_read_FTKhits_directly) {
-      vector<FTKHit> &curhits = m_reghits[curreg];
-      vector<FTKHit*> &curhits_read = *(m_reghits_read[curreg]);
-      curhits.clear();
-      vector<FTKHit*>::iterator ihit = curhits_read.begin();
-      for(; ihit!=curhits_read.end(); ++ihit){
-          FTKHit tmphit = **ihit;
-          curhits.push_back(tmphit);
-      }
-      
-  }
-  else {
-     // set the reference the list used by the current region
-     vector<FTKRawHit> &currawhits = *(m_original_reghits[curreg]);
-     vector<FTKHit> &curhits = m_reghits[curreg];
-
-     // reset hit list
-     curhits.clear();
-
-
-     if(FTKSetup::getDBG()) {
-       cout << "DBG: Original hits = " << currawhits.size() << endl;
-     }
-     m_nao_nhits_tot += currawhits.size();
-
-     if (!m_read_clusters) {
-         // if raw channels are read the clustering algorithm can be applyied (default)
-       if (m_Clustering ) {
-         atlClusteringLNF(currawhits);
-         atlClusteringBlayer(currawhits);  // split blayer modules in half, if requested
-       }
-       else {
-         // If the clustering it is not executed the FTKRawHit.m_truth field has to be fixed
-         vector<FTKRawHit>::iterator ihit = currawhits.begin();
-         vector<FTKRawHit>::const_iterator ihit_end = currawhits.end();
-         for (;ihit!=ihit_end;++ihit) { // loop over the raw hits
-       FTKRawHit &curhit = *ihit;
-       MultiTruth mt;
-       MultiTruth::Barcode uniquecode(curhit.getEventIndex(),curhit.getBarcode());
-       mt.maximize(uniquecode,curhit.getBarcodePt());
-       curhit.setTruth(mt);
-         } // end hit
-       }
-     }
-
-     if(FTKSetup::getDBG()) {
-       cout << "DBG: Clustered hits = " << m_original_hits.size() << endl;
-     }
-     m_nao_nclus_tot += currawhits.size();
-
-     // read SCTtrk values (Constantinos case) and push SCTtrk hits into hits vector:
-     // Note that it assumes the raw data input and root track input are fully in sync!
-     if(m_trackinput && m_roadinput) {
-       // for now, only read tracks from "current" region
-       int res = m_trackinput[curreg]->nextEvent();
-       if(res<0) {
-         FTKSetup::PrintMessage(ftk::sevr,"SCTtrk input ran out before hit input");
-       }
-       res = m_roadinput[curreg]->nextEvent();
-       if(res<0) {
-         FTKSetup::PrintMessage(ftk::sevr,"SCTtrk road input ran out before hit input");
-       }
-       const FTKTrack *cur_track = m_trackinput[curreg]->nextTrack(m_region);
-       while (cur_track) {
-         FTKRawHit tmphit(cur_track,m_pmap->getSCTtrkPlane());
-         m_original_hits.push_back(tmphit);
-         cur_track = m_trackinput[curreg]->nextTrack(m_region);
-       }
-     }
-
-     // filter the hit end convert input hit format into FTKHit
-     vector<FTKRawHit>::iterator irawhit = currawhits.begin();
-     FTKSetup &ftkset = FTKSetup::getFTKSetup();
-     
-     // create one list for each plane to order the hits
-     list<FTKHit> *planelist = new list<FTKHit>[m_nplanes];
-
-     for (;irawhit!=currawhits.end();++irawhit) { // loop over clusters
-       FTKRawHit &rawhit = *irawhit;
-
-       // check if end-cap hits should be accepted
-       if (rawhit.getBarrelEC()!=0 && ftkset.getBarrelOnly() == true) {
-         // skip this hit
-         continue;
-       }
-       // check if SCT hits should be accepted
-       if(rawhit.getIsSCT() && ftkset.getSCTtrkMode()) {
-         // skip this hit
-         continue;
-       }
-       if (m_pmap->getMap(rawhit.getHitType(),rawhit.getBarrelEC()!=0,rawhit.getLayer()).getPlane() != -1) {
-         // accept this hit
-         FTKHit tmphit = rawhit.getFTKHit(m_pmap);
-         if(rawhit.getTruth()!=nullptr)
-           tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
-         planelist[tmphit.getPlane()].push_front(tmphit);
-       }
-       else if (m_save_unused) {
-         // accept this hit
-         FTKHit tmphit = rawhit.getFTKHit(m_pmap_unused);
-         if(rawhit.getTruth()!=nullptr)
-           tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
-         m_hits_unused.push_back(tmphit);
-       }
-     } // end loop over clusters
-
-     for (int ipl=0;ipl<m_nplanes;++ipl) { // loop over the planes
-       list<FTKHit>::iterator tmphit = planelist[ipl].begin();
-       for (;tmphit!=planelist[ipl].end();++tmphit) {
-         curhits.push_back(*tmphit);
-       }
-     } // end loop over the planes
-
-     // clear raw hits since we don't need them anymore
-     if(clearOrig)
-       currawhits.clear();
-
-     delete [] planelist;
-  }
+
+    if (m_read_FTKhits_directly) {
+        vector<FTKHit> &curhits = m_reghits[curreg];
+        vector<FTKHit*> &curhits_read = *(m_reghits_read[curreg]);
+        curhits.clear();
+        vector<FTKHit*>::iterator ihit = curhits_read.begin();
+        for(; ihit!=curhits_read.end(); ++ihit){
+            FTKHit tmphit = **ihit;
+            curhits.push_back(tmphit);
+        }
+
+    }
+    else {
+        // set the reference the list used by the current region
+        vector<FTKRawHit> &currawhits = *(m_original_reghits[curreg]);
+        vector<FTKHit> &curhits = m_reghits[curreg];
+
+        // reset hit list
+        curhits.clear();
+
+
+        if(FTKSetup::getDBG()) {
+            cout << "DBG: Original hits = " << currawhits.size() << endl;
+        }
+        m_nao_nhits_tot += currawhits.size();
+
+        if (!m_read_clusters) {
+            // if raw channels are read the clustering algorithm can be applyied (default)
+            if (m_Clustering ) {
+                m_clusteringEngine->atlClusteringLNF(currawhits);
+                m_clusteringEngine->atlClusteringBlayer(currawhits);  // split blayer modules in half, if requested
+            }
+            else {
+                // If the clustering it is not executed the FTKRawHit.m_truth field has to be fixed
+                vector<FTKRawHit>::iterator ihit = currawhits.begin();
+                vector<FTKRawHit>::const_iterator ihit_end = currawhits.end();
+                for (;ihit!=ihit_end;++ihit) { // loop over the raw hits
+                    FTKRawHit &curhit = *ihit;
+                    MultiTruth mt;
+                    MultiTruth::Barcode uniquecode(curhit.getEventIndex(),curhit.getBarcode());
+                    mt.maximize(uniquecode,curhit.getBarcodePt());
+                    curhit.setTruth(mt);
+                } // end hit
+            }
+        }
+
+        if(FTKSetup::getDBG()) {
+            cout << "DBG: Clustered hits = " << m_original_hits.size() << endl;
+        }
+        m_nao_nclus_tot += currawhits.size();
+
+        // read SCTtrk values (Constantinos case) and push SCTtrk hits into hits vector:
+        // Note that it assumes the raw data input and root track input are fully in sync!
+        if(m_trackinput && m_roadinput) {
+            // for now, only read tracks from "current" region
+            int res = m_trackinput[curreg]->nextEvent();
+            if(res<0) {
+                FTKSetup::PrintMessage(ftk::sevr,"SCTtrk input ran out before hit input");
+            }
+            res = m_roadinput[curreg]->nextEvent();
+            if(res<0) {
+                FTKSetup::PrintMessage(ftk::sevr,"SCTtrk road input ran out before hit input");
+            }
+            const FTKTrack *cur_track = m_trackinput[curreg]->nextTrack(m_region);
+            while (cur_track) {
+                FTKRawHit tmphit(cur_track,m_pmap->getSCTtrkPlane());
+                m_original_hits.push_back(tmphit);
+                cur_track = m_trackinput[curreg]->nextTrack(m_region);
+            }
+        }
+
+        // filter the hit end convert input hit format into FTKHit
+        vector<FTKRawHit>::iterator irawhit = currawhits.begin();
+        FTKSetup &ftkset = FTKSetup::getFTKSetup();
+
+        // create one list for each plane to order the hits
+        list<FTKHit> *planelist = new list<FTKHit>[m_nplanes];
+
+        for (;irawhit!=currawhits.end();++irawhit) { // loop over clusters
+            FTKRawHit &rawhit = *irawhit;
+
+            // check if end-cap hits should be accepted
+            if (rawhit.getBarrelEC()!=0 && ftkset.getBarrelOnly() == true) {
+                // skip this hit
+                continue;
+            }
+            // check if SCT hits should be accepted
+            if(rawhit.getIsSCT() && ftkset.getSCTtrkMode()) {
+                // skip this hit
+                continue;
+            }
+            if (m_pmap->getMap(rawhit.getHitType(),rawhit.getBarrelEC()!=0,rawhit.getLayer()).getPlane() != -1) {
+                // accept this hit
+                FTKHit tmphit = rawhit.getFTKHit(m_pmap);
+                if(rawhit.getTruth()!=nullptr)
+                    tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
+                planelist[tmphit.getPlane()].push_front(tmphit);
+            }
+            else if (m_save_unused) {
+                // accept this hit
+                FTKHit tmphit = rawhit.getFTKHit(m_pmap_unused);
+                if(rawhit.getTruth()!=nullptr)
+                    tmphit.setTruth(*(rawhit.getTruth())); // AB - attach truth data to the FTKHit.
+                m_hits_unused.push_back(tmphit);
+            }
+        } // end loop over clusters
+
+        for (int ipl=0;ipl<m_nplanes;++ipl) { // loop over the planes
+            list<FTKHit>::iterator tmphit = planelist[ipl].begin();
+            for (;tmphit!=planelist[ipl].end();++tmphit) {
+                curhits.push_back(*tmphit);
+            }
+        } // end loop over the planes
+
+        // clear raw hits since we don't need them anymore
+        if(clearOrig)
+            currawhits.clear();
+
+        delete [] planelist;
+    }
 }
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKMergerAlgo.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKMergerAlgo.cxx
index c33f7808a1ce..cc85ba001e93 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKMergerAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKMergerAlgo.cxx
@@ -1420,17 +1420,7 @@ StatusCode FTKMergerAlgo::convertMergedTracks()
       << "entered execution for run " << eventID->run_number()
       << "   event " << eventNumber
       << endmsg;
-  
-  //
-  //  Get the primary vertex container
-  //
-  //   const VxContainer* primcontainer(0);
-  //   bool primVtxExists = evtStore()->contains<VxContainer>(m_vxCandidatesPrimaryName);
-  //   if(!primVtxExists){
-  //     log << MSG::INFO << "No VxContainer with key " << m_vxCandidatesPrimaryName << " found!" << endmsg;
-  //     cout << evtStore()->dump() << endl;
-  //   }
-  
+    
   // Extract the vector of tracks found by the FTK for the current event
   std::map<int, Long64_t >::iterator mapIt = m_trackVectorMap.find(eventNumber);
   if(mapIt == m_trackVectorMap.end()) {
@@ -2187,6 +2177,7 @@ void FTKMergerAlgo::merge_tracks(FTKTrackStream* &merged_tracks, FTKTrackStream
       if(!reg_tracks[ireg][isub]) continue;
       
       unsigned int ntracks = reg_tracks[ireg][isub]->getNTracks();
+      unsigned int ntracks_pre_hw = reg_tracks[ireg][isub]->getNTracks_pre_hw();
 
       merged_tracks->addNExtrapolatedTracks(reg_tracks[ireg][isub]->getNExtrapolatedTracks());
       merged_tracks->addNConnections(reg_tracks[ireg][isub]->getNConn());
@@ -2204,6 +2195,7 @@ void FTKMergerAlgo::merge_tracks(FTKTrackStream* &merged_tracks, FTKTrackStream
 
 
       unsigned int ntracksI = reg_tracks[ireg][isub]->getNTracksI();
+      unsigned int ntracksI_pre_hw = reg_tracks[ireg][isub]->getNTracksI_pre_hw();
       merged_tracks->addNCombsI(reg_tracks[ireg][isub]->getNCombsI());
       merged_tracks->addNFitsI(reg_tracks[ireg][isub]->getNFitsI());
       merged_tracks->addNFitsMajorityI(reg_tracks[ireg][isub]->getNFitsMajorityI());
@@ -2215,6 +2207,9 @@ void FTKMergerAlgo::merge_tracks(FTKTrackStream* &merged_tracks, FTKTrackStream
       merged_tracks->addNFitsHWRejectedI(reg_tracks[ireg][isub]->getNFitsHWRejectedI());
       merged_tracks->addNFitsBadMajorityI(reg_tracks[ireg][isub]->getNFitsBadMajorityI());
       merged_tracks->addNFitsHWRejectedMajorityI(reg_tracks[ireg][isub]->getNFitsHWRejectedMajorityI());
+
+      unsigned int ntracks_pattern = reg_tracks[ireg][isub]->getNTracks_pattern();
+      unsigned int ntracks_hits = reg_tracks[ireg][isub]->getNTracks_hits();
       
       for (unsigned int itr=0;itr!=ntracks;++itr) { // track loop
 
@@ -2266,14 +2261,35 @@ void FTKMergerAlgo::merge_tracks(FTKTrackStream* &merged_tracks, FTKTrackStream
 	}
       } // end track loop
 
+  for (unsigned int itr=0;itr!=ntracks_pre_hw;++itr) { // track loop (before Hit Warrior)
+    // get the track from the bank
+    FTKTrack &newtrack = *(reg_tracks[ireg][isub]->getTrack_pre_hw(itr));
+    merged_tracks->addTrack_pre_hw(newtrack);    
+  } // end loop over tracks of this bank (before Hit Warrior)
+
+  for (unsigned int itrI=0;itrI!=ntracksI;++itrI) { // intermediate track loop
+	  // get the track from the bank
+    FTKTrack &newtrack = *(reg_tracks[ireg][isub]->getTrackI(itrI));
+        // the intermediate tracks are not filtered by HW
+        merged_tracks->addTrackI(newtrack);
+      } // end intermediate track loop
 
+      for (unsigned int itrI=0;itrI!=ntracksI_pre_hw;++itrI) { // intermediate track loop (before Hit Warrior)
+        // get the track from the bank
+        FTKTrack &newtrack = *(reg_tracks[ireg][isub]->getTrackI_pre_hw(itrI));
+        merged_tracks->addTrackI_pre_hw(newtrack);
+      } // end intermediate track loop
 
-      for (unsigned int itrI=0;itrI!=ntracksI;++itrI) { // intermediate track loop
-	// get the track from the bank
-	FTKTrack &newtrack = *(reg_tracks[ireg][isub]->getTrackI(itrI));
-	
-	// the intermediate tracks are not filtered by HW
-	merged_tracks->addTrackI(newtrack);
+      for (unsigned int itrI=0;itrI!=ntracks_pattern;++itrI) { // intermediate track loop (tracks with patterns)
+        // get the track from the bank
+        FTKTrack &newtrack = *(reg_tracks[ireg][isub]->getTrack_pattern(itrI));
+        merged_tracks->addTrack_pattern(newtrack);
+      } // end intermediate track loop
+
+      for (unsigned int itrI=0;itrI!=ntracks_hits;++itrI) { // intermediate track loop (tracks that pass hits requirements)
+        // get the track from the bank
+        FTKTrack &newtrack = *(reg_tracks[ireg][isub]->getTrack_hits(itrI));
+        merged_tracks->addTrack_hits(newtrack);
       } // end intermediate track loop
 
     } // end subregion loop
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKPatternBySector.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKPatternBySector.cxx
index 88c33005c541..1bd3ce0a903b 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKPatternBySector.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKPatternBySector.cxx
@@ -348,8 +348,6 @@ int FTKPatternBySectorWriter::AppendMergedPatterns
 }
 #else
 
-const uint64_t FTKPatternBySectorWriter::PATTERN_CHUNK=20000000;
-
 
 int FTKPatternBySectorWriter::AppendMergedPatterns
 (FTKPatternBySectorReader &source,int minCoverage) {
@@ -369,7 +367,7 @@ int FTKPatternBySectorWriter::AppendMergedPatterns
    int readSector=source.GetFirstSector();
    while(readSector>=0) {
       std::list<FTKPatternOneSector *> sectorList;
-      readSector=source.ReadRaw(readSector,sectorList,PATTERN_CHUNK);
+      readSector=source.ReadRaw(readSector,sectorList,s_pattern_chunk);
       int nSector=0;
       int nPattern=0;
       for(std::list<FTKPatternOneSector *>::iterator iSector=sectorList.begin();
@@ -536,10 +534,8 @@ FTKPatternBySectorForestReader::FTKPatternBySectorForestReader(FTKRootFileChain
 }
 
 bool FTKPatternBySectorForestReader::CheckConsistency
-(FTKSSMap *ssMap,int tower,int hwmodeid) const {
-   if(ssMap &&(tower>=0) &&(hwmodeid>=0)) {
-      Warning("CheckConsistency")<<"not implemented\n";
-   }
+(FTKSSMap *,int,int) const {
+   Warning("CheckConsistency")<<"not implemented\n";
    return true;
 }
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKRoadFinderAlgo.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKRoadFinderAlgo.cxx
index baf22c90f27b..937000bfbb14 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKRoadFinderAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKRoadFinderAlgo.cxx
@@ -50,9 +50,8 @@ FTKRoadFinderAlgo::FTKRoadFinderAlgo(const std::string& name, ISvcLocator* pSvcL
   m_setAMSize(0), m_setAMSplit(0), m_maxAMAfterSplit(-1), m_minDVolOverDNPatt(0), 
   m_doMakeCache(0), m_CachePath("bankcache.root"),
   m_SaveAllRoads(0), m_StoreAllSS(0),
-  m_read_FTKhits_directly(false),
   m_pmap(0x0), m_pmap_unused(0x0),
-  m_rmap(0x0), m_rmap_unused(0x0),
+  m_rmap(0x0), m_rmap_unused(0x0), 
   m_ssmap(0x0), m_ssmap_unused(0x0), m_ssmap_tsp(0x0),
   m_require_first(false),
   m_HWModeSS(0),
@@ -71,7 +70,9 @@ FTKRoadFinderAlgo::FTKRoadFinderAlgo(const std::string& name, ISvcLocator* pSvcL
   m_SectorAsPatterns(0),
   m_DCMatchMethod(0),
   m_AutoDisable(false),
-  m_firstEventFTK(-1)
+  m_read_FTKhits_directly(false),
+  m_firstEventFTK(-1), 
+  m_AMcompressionMode(0)
 {
   // number of banks
   declareProperty("NBanks",m_nbanks);
@@ -145,6 +146,7 @@ FTKRoadFinderAlgo::FTKRoadFinderAlgo(const std::string& name, ISvcLocator* pSvcL
   declareProperty("DCMatchMethod",m_DCMatchMethod,"Set the DC matching method: 0 through TSP SS organization, 1 direct");
 
   declareProperty("FirstEventFTK",m_firstEventFTK,"First event to run over");
+  declareProperty("AMcompressionMode",m_AMcompressionMode,"compression mode for AM bank");
 }
 
 FTKRoadFinderAlgo::~FTKRoadFinderAlgo()
@@ -464,6 +466,7 @@ StatusCode FTKRoadFinderAlgo::initialize(){
           new FTK_CompressedAMBank(regid,subid);
        compressedBank->setSSMapTSP(m_ssmap_tsp);
        curbank=compressedBank;
+       compressedBank->setCompressionScheme(m_AMcompressionMode);
     } else {
       // configure a base AM bank
       curbank = new FTK_AMBank(regid,subid);
@@ -624,10 +627,11 @@ StatusCode FTKRoadFinderAlgo::finalize() {
 }
 
 void FTKRoadFinderAlgo::PostMessage() {
-   if(FTKLogger::m_type==0)  ATH_MSG_FATAL(m_buffer->str());
-   else if(FTKLogger::m_type==1)  ATH_MSG_ERROR(m_buffer->str());
-   else if(FTKLogger::m_type==2)  ATH_MSG_WARNING(m_buffer->str());
-   else if(FTKLogger::m_type==3)  ATH_MSG_INFO(m_buffer->str());
-   else if(FTKLogger::m_type==4)  ATH_MSG_DEBUG(m_buffer->str());
+   int fType=getLoggerMsgType();
+   if(fType==0) ATH_MSG_FATAL(getLoggerMsg());
+   else if(fType==1)  ATH_MSG_ERROR(getLoggerMsg());
+   else if(fType==2)  ATH_MSG_WARNING(getLoggerMsg());
+   else if(fType==3)  ATH_MSG_INFO(getLoggerMsg());
+   else if(fType==4)  ATH_MSG_DEBUG(getLoggerMsg());
 }
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrack.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrack.cxx
index 2421d9bb63a9..bbdbd2f02b42 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrack.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrack.cxx
@@ -2,6 +2,7 @@
   Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 */
 
+#include "TrigFTKSim/FTKSetup.h"
 #include "TrigFTKSim/FTKTrack.h"
 
 #include <iostream>
@@ -18,9 +19,10 @@ FTKTrack::FTKTrack() :
    m_invpt(0), m_d0(0), m_rawd0(0) , m_phi(0), m_rawphi(0), m_z0(0), m_rawz0(0),
    m_ctheta(0), m_chi2(0), m_origchi2(0), 
    m_invptfw(0), m_d0fw(0), m_phifw(0), m_z0fw(0), m_cthetafw(0), m_chi2fw(0),
-   m_nmissing(0), 
+   m_nmissing(0),
    m_typemask(0), m_bitmask(0), m_ncoords(0), m_coord(0),
    m_nplanes(0), m_hits(0x0),
+   m_nplanes_ignored(0), m_ssid(0),
    m_HF_rejected(0),m_HW_rejected(0),m_HW_track(-1),
    m_eventindex(-1), m_barcode(-1), m_barcode_frac(0.),
    m_connindex(-1)
@@ -79,6 +81,10 @@ FTKTrack::FTKTrack(const FTKTrack &cpy) :
    m_hits = new FTKHit[m_nplanes];
    for (int i=0;i!=m_nplanes;++i)
      m_hits[i] = cpy.m_hits[i];
+
+   m_nplanes_ignored = cpy.m_nplanes_ignored;
+   m_ssid = new int[m_nplanes_ignored];
+   for (int i=0;i<m_nplanes_ignored;++i) m_ssid[i] = cpy.m_ssid[i];
 }
 
 
@@ -88,9 +94,9 @@ FTKTrack::FTKTrack(const int &ncoords, const int &nplanes) :
    m_invpt(0), m_d0(0), m_rawd0(0), m_phi(0), m_rawphi(0), m_z0(0), m_rawz0(0),
    m_ctheta(0), m_chi2(0), m_origchi2(0), 
    m_invptfw(0), m_d0fw(0), m_phifw(0), m_z0fw(0), m_cthetafw(0), m_chi2fw(0),
-   m_nmissing(0), 
+   m_nmissing(0),
    m_typemask(0), m_bitmask(0),   m_ncoords(ncoords),
-   m_nplanes(nplanes),
+   m_nplanes(nplanes), m_nplanes_ignored(0), m_ssid(0),
    m_HF_rejected(0),m_HW_rejected(0),m_HW_track(-1),
    m_eventindex(-1), m_barcode(-1), m_barcode_frac(0.),
    m_connindex(-1) 
@@ -106,46 +112,51 @@ FTKTrack::~FTKTrack()
 {
    if (m_ncoords>0) delete [] m_coord;
    if (m_nplanes>0) delete [] m_hits;
+   if (m_nplanes_ignored>0) delete [] m_ssid;
 }
 
 // if ForceRange==true, then phi = [-pi..pi)
 void FTKTrack::setPhi(float phi, bool ForceRange) {
-  if (ForceRange) {
-    // when phi is ridiculously large, there is no point in adjusting it
-    if(fabs(phi)>100) {
-      if(m_chi2<100) { // this is a BAD track, so fail it if chi2 hasn't done so already
-	std::cout << "FTKTrack warning: fitted phi = " << phi << ", but chi2 = " << m_chi2 
-		  << ". Adjusting to chi2+=100!" << std::endl;
-	m_chi2+=100; // we want to fail this event anyway
-      }
-    }
-    else {
-      while (phi>= TMath::Pi()) phi -= TMath::TwoPi(); 
-      while (phi< -TMath::Pi()) phi += TMath::TwoPi();
-    }
+  if (ForceRange && fabs(phi)>100 && m_chi2<100) {
+    // when phi is ridiculously large, there is no point in adjusting it. Also, since this is a BAD track, fail it if chi2 hasn't done so already
+    FTKSetup::PrintMessageFmt(ftk::warn, "FTKTrack warning: fitted phi = %f, but chi2 = %f. Adjusting to chi2+=100!", phi, m_chi2);
+    m_chi2+=100; // we want to fail this event anyway
+  }
+  else if (ForceRange && fabs(phi)<100){
+    while (phi>= TMath::Pi()) phi -= TMath::TwoPi(); 
+    while (phi< -TMath::Pi()) phi += TMath::TwoPi();
   }
   m_phi = phi;
 }
 
 // if ForceRange==true, then phi = [-pi..pi)
 void FTKTrack::setPhiRaw(float phi, bool ForceRange) {
-  if (ForceRange) {
-    // when phi is ridiculously large, there is no point in adjusting it
-    if(fabs(phi)>100) {
-      if(m_chi2<100) { // this is a BAD track, so fail it if chi2 hasn't done so already
-	std::cout << "FTKTrack warning: fitted phi = " << phi << ", but chi2 = " << m_chi2 
-		  << ". Adjusting to chi2+=100!" << std::endl;
-	m_chi2+=100; // we want to fail this event anyway
-      }
-    }
-    else {
-      while (phi>= TMath::Pi()) phi -= TMath::TwoPi(); 
-      while (phi< -TMath::Pi()) phi += TMath::TwoPi();
-    }
+  if (ForceRange && fabs(phi)>100 && m_chi2<100) {
+    // when phi is ridiculously large, there is no point in adjusting it. Also, since this is a BAD track, fail it if chi2 hasn't done so already
+    FTKSetup::PrintMessageFmt(ftk::warn, "FTKTrack warning: fitted phi = %f, but chi2 = %f. Adjusting to chi2+=100!", phi, m_chi2);
+    m_chi2+=100; // we want to fail this event anyway
+  }
+  else if (ForceRange && fabs(phi)<100){
+    while (phi>= TMath::Pi()) phi -= TMath::TwoPi(); 
+    while (phi< -TMath::Pi()) phi += TMath::TwoPi();
   }
   m_rawphi = phi;
 }
 
+// if ForceRange==true, then phifw = [-3..3)
+void FTKTrack::setPhiFW(int phifw, bool ForceRange) {
+  // when phifw is ridiculously large, there is no point in adjusting it. Also, since this is a BAD track, fail it if chi2 hasn't done so already
+  if (ForceRange && abs(phifw)>100 && m_chi2fw<100) {
+    FTKSetup::PrintMessageFmt(ftk::warn, "FTKTrack warning: fitted phifw = %d, but chi2fw = %d. Adjusting to chi2fw+=100!", phifw, m_chi2fw);
+    m_chi2fw+=100; // we want to fail this event anyway
+  }
+  else if (ForceRange && abs(phifw)<100) {
+    while (phifw>= round(TMath::Pi())) phifw -= round(TMath::TwoPi()); 
+    while (phifw< -round(TMath::Pi())) phifw += round(TMath::TwoPi());
+  }
+  m_phifw = phifw;
+}
+
 /** set the number of coordinates connected with this track,
     a dim=0 is used to cleanup array content */
 void FTKTrack::setNCoords(int dim)
@@ -168,6 +179,17 @@ void FTKTrack::setNPlanes(int dim)
   m_hits = new FTKHit[m_nplanes];
 }
 
+/** set the number of planes to extrapolate the 7L tracks,
+    a dim=0 is used to cleanup array content */
+void FTKTrack::setNPlanesIgnored(int dim)
+{
+  if (m_nplanes_ignored>0) delete [] m_ssid;
+
+  m_nplanes_ignored = dim;
+  m_ssid = new int[m_nplanes_ignored];
+  for (int i=0; i<m_nplanes_ignored; ++i) m_ssid[i] = 0;
+}
+
 
 float FTKTrack::getParameter(int ipar, bool useraw) const
 {
@@ -220,6 +242,44 @@ void  FTKTrack::setParameter(int ipar, float val, bool useraw)
   }
 }
 
+/** return the number of the common hits for the first stage (AUX).
+The current formatting has coordinates instead of hits, so pixel x and y are checked separately.
+However, we only consider a hit matched if all coordinates in the hit match.
+*/
+unsigned int FTKTrack::getNCommonHitsFirstStage(const FTKTrack &track, const float *HWdev) const
+{
+  unsigned int ncommon_hits(0);
+
+  // match over the hits list
+  int hit_ready=0;//Hit_ready is 0 if we still need two coords to match, 1 if we only need one more
+  //This loop is over coordinates, which includes pixel x, pixel y, and sct
+  for (int ix=0;ix!=m_ncoords;++ix) {
+    //Only want it to count as match if pixel x and y both match
+    if (ix>(m_ncoords == 11 ? 5 : 7)) { //SCT hit (3 pixel hits when 11 coord, 4 when 16 coord)
+        hit_ready=1; //If we're on an SCT hit, we only need one coordinate match to say the hit matches
+    } else if (ix==0 || ix==2 || ix==4) {//Beginning of pixel hit
+        hit_ready=0; //Pixel hits require two coordinates to match
+    }
+
+    if ( !((m_bitmask & track.m_bitmask) & (1<<ix)) ) {
+      // majority hits are never counted as matched
+      continue;
+    }
+
+    double dist = TMath::Abs(getCoord(ix)-track.getCoord(ix));
+    if ( dist < HWdev[ix] ) {
+      if ( hit_ready == 1) { //Either this is SCT, or we already found that pixel x matches
+        ++ncommon_hits; // a common hit
+      } else {
+        //The pixel x matches, y checked on next iteration of loop
+        hit_ready=1;
+      }
+    }
+  } // end loop over coordinates
+
+  return ncommon_hits;
+}
+
 /** return the number of the common hits */
 unsigned int FTKTrack::getNCommonHits(const FTKTrack &track, const float *HWdev) const
 {
@@ -242,13 +302,8 @@ unsigned int FTKTrack::getNCommonHits(const FTKTrack &track, const float *HWdev)
   return ncommon_hits;
 }
 
-
-/** this function compare this track with a different tracks and returns:
-     0 if according HW setup the two tracks are different
-     1 are similar and the other has a worse quality parameter
-     -1 are similar and the other has a better quality parameter */
 int FTKTrack::HWChoice(const FTKTrack &other, const float *HW_dev,
-		       const unsigned int HW_ndiff, int HW_level)
+               const unsigned int HW_ndiff, int HW_level)
 {
   int accepted(0);
 
@@ -266,24 +321,24 @@ int FTKTrack::HWChoice(const FTKTrack &other, const float *HW_dev,
   if ( m_ncoords-ncommon_hits<=HW_ndiff) { 
     // the track matches
     if ( ( getHWRejected() && !other.getHWRejected()) ||
-	 (!getHWRejected() &&  other.getHWRejected()) ) {
-	    
+     (!getHWRejected() &&  other.getHWRejected()) ) {
+        
       // keep the track in the accepted road
       if (getHWRejected()) {
-	accepted = -1;
+    accepted = -1;
       }
       else {
-	accepted = 1;
+    accepted = 1;
       }
-	    
+        
     }
     else if (other.getNMissing()==getNMissing()) {
       // keep the track with the best chi2
       if (other.getChi2() > getChi2()) {
-	accepted = 1;
+    accepted = 1;
       }
       else {
-	accepted = -1;
+    accepted = -1;
       }
     }
     else if (other.getNMissing() < getNMissing()) {
@@ -299,6 +354,54 @@ int FTKTrack::HWChoice(const FTKTrack &other, const float *HW_dev,
 }
 
 
+/** this function compare this track with a different tracks for the AUX
+     (First stage) and returns:
+     0 if according HW setup the two tracks are different
+     1 are similar and the other has a worse quality parameter
+     -1 are similar and the other has a better quality parameter */
+int FTKTrack::HWChoiceFirstStage(const FTKTrack &other, const float *HW_dev,
+		       const unsigned int HW_ndiff, int HW_level)
+{
+  int accepted(0);
+
+  // Choose hitwarrior severity level: 1=in-road, 2=global
+  //The parent function is run at road-level, so severity has to be 1 for now
+  if(HW_level<2) {
+    if(getBankID()!=other.getBankID()) return accepted;
+    if(getRoadID()!=other.getRoadID()) return accepted;
+  }
+
+  unsigned int ncommon_hits = getNCommonHitsFirstStage(other,HW_dev);
+  // FlagAK - simplistic hitwarrior. Makes no distinction between 1D and 2D
+  // If this doesn't work, we'll need to come up with something smarter
+  // check the criteria for considering two tracks the same
+  if (ncommon_hits>=HW_ndiff) {//Simple comparison to threshold number of matched hits
+    // the track matches
+
+    //We should never have more than 1 missing hit in the AUX HW. Necessary because NMissing double-counts pixel hits
+    if ((other.getNMissing()==0 && getNMissing()==0) || (other.getNMissing()>0 && getNMissing()>0)) {
+      // keep the track with the best chi2
+      if (other.getChi2() > getChi2()) {
+	accepted = 1;
+      }
+      else {
+	accepted = -1;
+      }
+    }
+    //If first stage, then the track with fewer missing hits must have 0 missing
+    else if (other.getNMissing() == 0) {
+      // keep the track using more real points
+      accepted = -1;
+    }
+    else if (getNMissing()==0) {
+      accepted = 1;
+    }
+  }
+
+  return accepted;
+}
+
+
 FTKTrack& FTKTrack::operator=(const FTKTrack &tocpy)
 {
 #ifdef PROTECT_SA // speedup
@@ -369,6 +472,17 @@ FTKTrack& FTKTrack::operator=(const FTKTrack &tocpy)
           m_hits[i] = tocpy.m_hits[i];
         }
       }
+
+      if (m_nplanes_ignored!=tocpy.m_nplanes_ignored) {    
+        m_nplanes_ignored  = tocpy.m_nplanes_ignored;   
+        if (m_ssid) delete [] m_ssid;
+        m_ssid = new int[m_nplanes_ignored];
+      }
+      else {
+        for (int i=0;i<m_nplanes_ignored;++i) {
+          m_ssid[i] = tocpy.m_ssid[i];
+        }
+      }
     }
 
   return *this;
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFileOutput.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFileOutput.cxx
index 8483438bff90..1cc294e60337 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFileOutput.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFileOutput.cxx
@@ -23,6 +23,12 @@ void FTKTrackFileOutput::addTrack(int ibank, const FTKTrack &track)
   m_data[ibank]->addTrack(track);
 }
 
+/** add roads to a bank with a given ID */
+void FTKTrackFileOutput::addTrack_pre_hw(int ibank, const FTKTrack &track)
+{
+  // create a new element into the clones array
+  m_data[ibank]->addTrack_pre_hw(track);
+}
 
 /** add roads to a bank with a given ID */
 void FTKTrackFileOutput::addTrackI(int ibank, const FTKTrack &track)
@@ -30,3 +36,24 @@ void FTKTrackFileOutput::addTrackI(int ibank, const FTKTrack &track)
   // create a new element into the clones array
   m_data[ibank]->addTrackI(track);
 }
+
+/** add roads before Hit Warrior to a bank with a given ID */
+void FTKTrackFileOutput::addTrackI_pre_hw(int ibank, const FTKTrack &track)
+{
+  // create a new element into the clones array
+  m_data[ibank]->addTrackI_pre_hw(track);
+}
+
+/** add roads with patterns to a bank with a given ID */
+void FTKTrackFileOutput::addTrack_pattern(int ibank, const FTKTrack &track)
+{
+  // create a new element into the clones array
+  m_data[ibank]->addTrack_pattern(track);
+}
+
+/** add roads passing hits requirements to a bank with a given ID */
+void FTKTrackFileOutput::addTrack_hits(int ibank, const FTKTrack &track)
+{
+  // create a new element into the clones array
+  m_data[ibank]->addTrack_hits(track);
+}
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFitterAlgo.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFitterAlgo.cxx
index f1924a6a2add..24782e9a15c7 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFitterAlgo.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackFitterAlgo.cxx
@@ -34,10 +34,11 @@ FTKTrackFitterAlgo::FTKTrackFitterAlgo(const std::string& name, ISvcLocator* pSv
   m_chi2cut(17),
   m_chi2cut_maj(14),
   m_chi2cut_vetmaj(-1),
-  m_chi2dofcut(4),
+  m_chi2dofcutAux(4),
+  m_chi2dofcutSSB(4),
   m_doAuxFW(false),
   m_HitWarrior(2),
-  m_HitWarrior_first(1),
+  m_AuxDoctor(false),
   m_KeepRejected(0), 
   m_FitRemoved(0),
   m_DoMajority(1),
@@ -57,6 +58,7 @@ FTKTrackFitterAlgo::FTKTrackFitterAlgo(const std::string& name, ISvcLocator* pSv
   m_SSF_TR_min_eta(1.0),
   m_SSF_TR_max_eta(1.4),
   m_save_1stStageTrks(false),
+  m_save_StepByStepTrks(false),
   m_doTrackFile(false),
   m_addRoads(false),
   m_trackfilepath("./"), 
@@ -79,10 +81,11 @@ FTKTrackFitterAlgo::FTKTrackFitterAlgo(const std::string& name, ISvcLocator* pSv
   declareProperty("Chi2Cut",m_chi2cut);
   declareProperty("Chi2Cut_Maj",m_chi2cut_maj);
   declareProperty("Chi2Cut_VetoMaj",m_chi2cut_vetmaj);
-  declareProperty("Chi2DofCut",m_chi2dofcut);
+  declareProperty("Chi2DofCutAux",m_chi2dofcutAux);
+  declareProperty("Chi2DofCutSSB",m_chi2dofcutSSB);
   declareProperty("doAuxFW", m_doAuxFW);
   declareProperty("HitWarrior", m_HitWarrior);
-  declareProperty("FirstStageHitWarrior", m_HitWarrior_first);
+  declareProperty("AuxDoctor", m_AuxDoctor);
   declareProperty("KeepRejected", m_KeepRejected);
   declareProperty("FitRemoved", m_FitRemoved);
   declareProperty("DoMajority",m_DoMajority);
@@ -112,6 +115,7 @@ FTKTrackFitterAlgo::FTKTrackFitterAlgo(const std::string& name, ISvcLocator* pSv
   declareProperty("ssmapunused_path",m_ssmapunused_path);
   declareProperty("TRACKFITTER_MODE",m_SSF_TFMode);
   declareProperty("Save1stStageTrks",m_save_1stStageTrks);
+  declareProperty("SaveStepByStepTrks",m_save_StepByStepTrks);
   declareProperty("SSFMultiConnection",m_SSF_multiconn);
   declareProperty("SSFNConnections",m_SSF_maxnconn);
   declareProperty("SSFAllowExtraMiss",m_SSF_allow_extramiss);
@@ -283,6 +287,7 @@ StatusCode FTKTrackFitterAlgo::initialize(){
     
 
     // std::size_t replace_index = m_trackfilename.find(".root");
+
     // string pre_hw_trackfilename = m_trackfilename;
     // if (replace_index != std::string::npos) pre_hw_trackfilename.insert(replace_index, "_pre_hw");  
     // ftkouttrackmodule_pre_hw->setMultiOut(false);
@@ -342,10 +347,11 @@ StatusCode FTKTrackFitterAlgo::initialize(){
   // set parameter object to TrackFitter
   m_tfpobj->setChi2Cut(m_chi2cut);
   m_tfpobj->setHitWarrior(m_HitWarrior);
-  m_tfpobj->setHitWarriorFirst(m_HitWarrior_first);
+  m_tfpobj->setAuxDoctor(m_AuxDoctor);
   m_tfpobj->setChi2Cut_maj(m_chi2cut_maj);
   m_tfpobj->setChi2Cut_vetomaj(m_chi2cut_vetmaj);
-  m_tfpobj->setChi2DofCut(m_chi2dofcut);
+  m_tfpobj->setChi2DofCutAux(m_chi2dofcutAux);
+  m_tfpobj->setChi2DofCutSSB(m_chi2dofcutSSB);
   m_tfpobj->setKeepRejected(m_KeepRejected); 
   m_tfpobj->setFitRemoved(m_FitRemoved);
   m_tfpobj->setHWNDiff(m_HWNDiff);
@@ -356,6 +362,9 @@ StatusCode FTKTrackFitterAlgo::initialize(){
   m_tfpobj->setRequireFirst(0);
   m_tfpobj->setOnePerRoad(m_OnePerRoad);
 
+  if (m_save_StepByStepTrks) m_tfpobj->setSaveStepByStepTracks(true);
+  else m_tfpobj->setSaveStepByStepTracks(false);
+
   //std::cout << "chi2cut "        << m_tfpobj->getChi2Cut()         << std::endl;
   //std::cout << "hitwarr "        << m_tfpobj->getHitWarrior()      << std::endl;
   //std::cout << "chi2cutmaj "     << m_tfpobj->getChi2Cut_maj()     << std::endl;
@@ -395,9 +404,9 @@ StatusCode FTKTrackFitterAlgo::initialize(){
     else
       dynamic_cast<TrackFitter711*>(m_tfpobj)->setSuperExtrapolateMode(false);
     if (m_save_1stStageTrks)
-      dynamic_cast<TrackFitter*>(m_tfpobj)->setSaveIncompleteTracks(true);
+      dynamic_cast<TrackFitter711*>(m_tfpobj)->setSaveIncompleteTracks(true);
     else
-      dynamic_cast<TrackFitter*>(m_tfpobj)->setSaveIncompleteTracks(false);
+      dynamic_cast<TrackFitter711*>(m_tfpobj)->setSaveIncompleteTracks(false);
 
     dynamic_cast<TrackFitter711*>(m_tfpobj)->setUseSectorDB(true);
     dynamic_cast<TrackFitter711*>(m_tfpobj)->setUseMultipleConn(m_SSF_multiconn);
@@ -470,10 +479,10 @@ StatusCode FTKTrackFitterAlgo::initialize(){
 
 	log << MSG::INFO << "*** Printing EXP and TF constants in a txt file ****" << endmsg;
 
-        std::ofstream myfile;
+	std::ofstream myfile;
 	myfile.open (Form("EXPConstants_reg%d.txt",ir));
 
-        std::ofstream myfileTF;
+	std::ofstream myfileTF;
 	myfileTF.open (Form("TFConstants_reg%d.txt",ir));
 
 	std::vector<std::map <int, int> > vecOfMapSecID;
@@ -482,7 +491,7 @@ StatusCode FTKTrackFitterAlgo::initialize(){
 	vecOfMapNconn.clear();
 
 	log << MSG::INFO << "*** Reading the connection file and mapping 8L -> 12L " << endmsg;
-        std::vector<std::vector<int>> moduleIDvec;
+	std::vector<std::vector<int>> moduleIDvec;
 	moduleIDvec.clear();
 
 	Int_t Max_1stStage_sectors = 16383;
@@ -500,7 +509,7 @@ StatusCode FTKTrackFitterAlgo::initialize(){
 	    Map_temp[TwelveLsecid] = (int)sector->getNSimilarSectors(isec) ;
 	    vecOfMapNconn.push_back(Map_temp);
 	    vecOfMapSecID.push_back(Map_secid_Nconn);
-            std::vector<int> module_temp;
+	    std::vector<int> module_temp;
 	    module_temp.clear();
 	    for (int ip=0; ip!=(m_pmap_complete->getNPlanes()-m_pmap->getNPlanes()); ++ip) {
 	      module_temp.push_back(sector->getSimilarStereoIDs(isec,Nconn)[ip]);
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackStream.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackStream.cxx
index 8bfd7fec86b7..4a21d0710933 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackStream.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTKTrackStream.cxx
@@ -10,19 +10,24 @@ using namespace std;
 
 FTKTrackStream::FTKTrackStream() :
   m_run_number(0ul), m_event_number(0ul),
-  m_ntracks(0), m_ncombs(0),m_nfits(0), m_nfits_maj(0),
+  m_ntracks(0), m_ntracks_pre_hw(0), m_ncombs(0),m_nfits(0), m_nfits_maj(0),
   m_nfits_maj_SCT(0),
   m_nfits_maj_pix(0),
   m_nfits_rec(0), m_nfits_addrec(0), m_nfits_bad(0), m_nfits_rej(0),
   m_nfits_badmaj(0), m_nfits_rejmaj(0),
-  m_ntracksI(0), m_ncombsI(0),m_nfitsI(0), m_nfits_majI(0),
+  m_ntracksI(0), m_ntracksI_pre_hw(0), m_ncombsI(0), m_nfitsI(0), m_nfits_majI(0),
   m_nfits_majI_SCT(0),
   m_nfits_majI_pix(0),
   m_nfits_recI(0), m_nfits_addrecI(0), m_nfits_badI(0), m_nfits_rejI(0),
-  m_nfits_badmajI(0), m_nfits_rejmajI(0), m_nconn(0), m_nextrapolatedTracks(0)
+  m_nfits_badmajI(0), m_nfits_rejmajI(0), m_nconn(0), m_nextrapolatedTracks(0),
+  m_ntracks_pattern(0), m_ntracks_hits(0)
 {
   m_tracks = new TClonesArray("FTKTrack",1000);
+  m_tracks_pre_hw = new TClonesArray("FTKTrack",1000);
   m_tracksI = new TClonesArray("FTKTrack",1000);
+  m_tracksI_pre_hw = new TClonesArray("FTKTrack",1000);
+  m_tracks_pattern = new TClonesArray("FTKTrack",1000);
+  m_tracks_hits = new TClonesArray("FTKTrack",1000);
 }
 
 
@@ -30,8 +35,16 @@ FTKTrackStream::~FTKTrackStream()
 {
   m_tracks->Delete();
   delete m_tracks;
+  m_tracks_pre_hw->Delete();
+  delete m_tracks_pre_hw;
   m_tracksI->Delete();
   delete m_tracksI;
+  m_tracksI_pre_hw->Delete();
+  delete m_tracksI_pre_hw;
+  m_tracks_pattern->Delete();
+  delete m_tracks_pattern;
+  m_tracks_hits->Delete();
+  delete m_tracks_hits;
 }
 
 
@@ -42,6 +55,11 @@ void FTKTrackStream::addTrack(const FTKTrack &track)
   m_trackIdMap[std::make_pair(track.getTrackID(),track.getBankID())] = m_ntracks-1; 
 }
 
+/** add a track in the final list */
+void FTKTrackStream::addTrack_pre_hw(const FTKTrack &track)
+{
+  new ((*m_tracks_pre_hw)[m_ntracks_pre_hw++]) FTKTrack(track); 
+}
 
 /** return a given track, identified by its position in 
     the list */
@@ -51,6 +69,14 @@ FTKTrack* FTKTrackStream::getTrack(int ipos) const
   else return (FTKTrack*)m_tracks->At(ipos);
 }
 
+/** return a given track, identified by its position in 
+    the list */
+FTKTrack* FTKTrackStream::getTrack_pre_hw(int ipos) const
+{
+  if (ipos>=m_ntracks_pre_hw) return 0;
+  else return (FTKTrack*)m_tracks_pre_hw->At(ipos);
+}
+
 /** this method, passing a track ID and a bank ID, return the ID 
     of the corresponding track. If it doesn't exist return -1 */
 int FTKTrackStream::findTrack(int trackid, int bankid)
@@ -65,13 +91,17 @@ int FTKTrackStream::findTrack(int trackid, int bankid)
     return -1;
 }
 
-
 /** add a track in the final list */
 void FTKTrackStream::addTrackI(const FTKTrack &track)
 {
   new ((*m_tracksI)[m_ntracksI++]) FTKTrack(track); 
 }
 
+/** add a track in the final list */
+void FTKTrackStream::addTrackI_pre_hw(const FTKTrack &track)
+{
+  new ((*m_tracksI_pre_hw)[m_ntracksI_pre_hw++]) FTKTrack(track); 
+}
 
 /** return a given track, identified by its position in 
     the list */
@@ -81,6 +111,42 @@ FTKTrack* FTKTrackStream::getTrackI(int ipos) const
   else return (FTKTrack*)m_tracksI->At(ipos);
 }
 
+/** return a given track, identified by its position in 
+    the list */
+FTKTrack* FTKTrackStream::getTrackI_pre_hw(int ipos) const
+{
+  if (ipos>=m_ntracksI_pre_hw) return 0;
+  else return (FTKTrack*)m_tracksI_pre_hw->At(ipos);
+}
+
+/** add a track in the final list */
+void FTKTrackStream::addTrack_pattern(const FTKTrack &track)
+{
+  new ((*m_tracks_pattern)[m_ntracks_pattern++]) FTKTrack(track); 
+}
+
+/** add a track in the final list */
+void FTKTrackStream::addTrack_hits(const FTKTrack &track)
+{
+  new ((*m_tracks_hits)[m_ntracks_hits++]) FTKTrack(track); 
+}
+
+/** return a given track, identified by its position in 
+    the list */
+FTKTrack* FTKTrackStream::getTrack_pattern(int ipos) const
+{
+  if (ipos>=m_ntracks_pattern) return 0;
+  else return (FTKTrack*)m_tracks_pattern->At(ipos);
+}
+
+/** return a given track, identified by its position in 
+    the list */
+FTKTrack* FTKTrackStream::getTrack_hits(int ipos) const
+{
+  if (ipos>=m_ntracks_hits) return 0;
+  else return (FTKTrack*)m_tracks_hits->At(ipos);
+}
+
 /** reset the list of the tracks and the statistical informatino
     collected for this event */
 void FTKTrackStream::clear()
@@ -90,8 +156,16 @@ void FTKTrackStream::clear()
 
   m_tracks->Delete();
   m_ntracks = 0;
+  m_tracks_pre_hw->Delete();
+  m_ntracks_pre_hw = 0;
   m_tracksI->Delete();
   m_ntracksI = 0;
+  m_tracksI_pre_hw->Delete();
+  m_ntracksI_pre_hw = 0;
+  m_tracks_pattern->Delete();
+  m_ntracks_pattern = 0;
+  m_tracks_hits->Delete();
+  m_ntracks_hits = 0;
 
   m_ncombs = 0;
   m_nfits = 0;
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMBank.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMBank.cxx
index 2939f76af754..df759cd0bddb 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMBank.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMBank.cxx
@@ -636,7 +636,6 @@ int FTK_AMBank::readROOTBankSectorOrdered(TFile* pattfile, int maxpatt)
             m_patternCoverage[patternID] = coverage;
             m_totalCoverage += coverage;
             (*m_sectorCoverage)[m_patterns[_SSPOS(patternID,m_nplanes)]] += m_patternCoverage[patternID];
-	 //cout<<sector<<" "<<coverage<<" "<<endl; //hier
 
             patternID++; // increment the global pattern ID
          } // end for (patterns)
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMsimulation_base.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMsimulation_base.cxx
index d20ec8e22fe1..b57d19d89cae 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMsimulation_base.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_AMsimulation_base.cxx
@@ -8,6 +8,7 @@
 #include <iomanip>
 
 //#define VERBOSE_DEBUG
+#define PRINT_IBL_HITS 0
 
 using namespace std;
 
@@ -201,7 +202,7 @@ int FTK_AMsimulation_base::passHitsUnused(const std::vector<FTKHit> &hitlist) {
 
     std::map<int,FTKSS>::iterator issitem = ssmap.find(ssid);
     if (issitem==ssmap.end()) {
-      // ad the item related to this SS number
+      // add the item related to this SS number
       ssmap[ssid] = FTKSS();
       issitem = ssmap.find(ssid);
     }
@@ -212,6 +213,43 @@ int FTK_AMsimulation_base::passHitsUnused(const std::vector<FTKHit> &hitlist) {
   if(error) {
      FTKSetup::PrintMessageFmt(ftk::warn,"FTK_AMsimulation_base::passHitsUnused number or errors=%d\n",error );
   }
+  static int print=PRINT_IBL_HITS;
+  if(print) {
+     cout<<"PassHitsUnused\n";
+     for(std::map< int, std::map< int, FTKSS > >::const_iterator
+            ipl=m_usedssmap_ignored.begin();
+         ipl!=m_usedssmap_ignored.end();ipl++) {
+        cout<<"unused plane="<<(*ipl).first<<" nSS="<<(*ipl).second.size();
+        int nhit=0;
+        int lastHash=-1;
+        for(std::map< int, FTKSS >::const_iterator ihit=(*ipl).second.begin();
+            ihit!=(*ipl).second.end();ihit++) {
+           nhit+= (*ihit).second.getNHits();
+           if((*ipl).first==0) {
+              int localID,localX,localY;
+              getSSMapUnused()->decodeSSTowerXY((*ihit).first,
+                                                getBankID(),(*ipl).first,0,
+                                                localID,localX,localY,true);
+              int hash=getSSMapUnused()->getRegionMap()
+                 ->getGlobalId(getBankID(),(*ipl).first,localID);
+              if(hash!=lastHash) {
+                 cout<<"\nModule="<<hash;
+                 lastHash=hash;
+              }
+              cout<<" "<<(*ihit).first;
+              //<<":"<<localX<<","<<localY;
+              for(int ih=0;ih<(*ihit).second.getNHits();ih++) {
+                 const FTKHit &h=(*ihit).second.getHit(ih);
+                 cout<<"["<<h[0]<<","<<h[1]<<"]";
+              }
+           }
+        }
+        cout<<" nhit="<<nhit;
+        cout<<"\n";
+     }
+     print--;
+  }
+
   return res;
 }
 
@@ -407,17 +445,13 @@ class SSIDordering {
  */
 void FTK_AMsimulation_base::printRoads(list<FTKRoad> const &roads,
                                        int printSectorID) const {
-   map<int,map<vector<int>,FTKRoad const *> > roadMap;
+   map<int,map<int,FTKRoad const *> > roadMap;
    for(list<FTKRoad>::const_iterator iroad=roads.begin();
        iroad!=roads.end();iroad++) {
-      vector<int> ssid(getNPlanes());
-      for(int i=0;i<getNPlanes();i++) {
-         ssid[i]=(*iroad).getSSID(i);
-      }
-      roadMap[(*iroad).getSectorID()][ssid]=& *iroad;
+      roadMap[(*iroad).getSectorID()][(*iroad).getPatternID()]=& *iroad;
    }
    cout<<"number of sectors with roads: "<<roadMap.size()<<"\n";
-   for(map<int,map<vector<int>,FTKRoad const *> >::const_iterator i=
+   for(map<int,map<int,FTKRoad const *> >::const_iterator i=
           roadMap.begin();i!=roadMap.end();i++) {
       if(((*i).first==printSectorID)||
          (printSectorID<0)) {
@@ -427,7 +461,7 @@ void FTK_AMsimulation_base::printRoads(list<FTKRoad> const &roads,
             cout<<"=SSID"<<i;
          }
          cout<<"==BITMASK==ROAD===PATTID====DBID======HLIDbIDregSub=SR====SubSS=DCmask=HLmask\n";
-         for(map<vector<int>,FTKRoad const *>::const_iterator
+         for(map<int,FTKRoad const *>::const_iterator
                 iroad=(*i).second.begin();
              iroad!=(*i).second.end();iroad++) {
             FTKRoad const *road=(*iroad).second;
@@ -452,7 +486,7 @@ void FTK_AMsimulation_base::printRoads(list<FTKRoad> const &roads,
                 <<setw(3)<<road->getSubRegion()
                 <<setw(3)<<road->getNSubRoads()<<" "<<setbase(16);
             for(int i=0;i<road->getNPlanes();i++) {
-               cout<<road->getSubSSMask(i);
+               cout<<setw(2)<<road->getSubSSMask(i);
             }
             cout<<setw(7)<<road->getDCBitmask()<<setw(7)<<road->getHLBitmask();
             cout<<setbase(10);
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedAMBank.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedAMBank.cxx
index 6c146e5663b6..1489a642c8ff 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedAMBank.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedAMBank.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "TrigFTKSim/FTK_CompressedAMBank.h"
@@ -19,6 +19,23 @@
 #include <TString.h>
 #include <TRegexp.h>
 
+#define QSORT_FOR_DC_IMPORT
+
+#define PRINT_ROADS_SECTORID -1
+#define PRINT_ROADSUMMARY_NEVENT 2
+//#define PRINT_DETAILS_NEVENT 2
+// PRINT_SS is per plane
+// #define PRINT_SS 8
+//#define PRINT_SS_DETAIL
+// #define WRITE_DEADMODULE_TEMPLATE
+// #define TESTDCSSID 19
+//#define DEBUG_EVENT 88
+
+//#define DEBUG
+
+#define HW2_USE_TSPMAP
+
+// #define SEARCH_MEMORY_LEAK
 
 #ifdef SEARCH_MEMORY_LEAK
 #include <sys/time.h>
@@ -44,23 +61,9 @@ static void printVmemUsage(char const *text) {
 
  */
 
-#define QSORT_FOR_DC_IMPORT
-
-#define PRINT_ROADS_SECTORID -1
-#define PRINT_DETAILS_NEVENT 0
-//#define PRINT_DETAILS_NEVENT 100
-#define PRINT_SS 0
-//#define PRINT_SS PRINT_DETAILS_NEVENT
-#define PRINT_SS_NOROAD 0
-//#define PRINT_SS_NOROAD PRINT_DETAILS_NEVENT
-// #define PRINT_MULTIPLICITY
-// #define WRITE_DEADMODULE_TEMPLATE
-// #define TESTDCSSID 19
-//#define DEBUG_EVENT 88
-
-#define HW2_USE_TSPMAP
-
-int const FTK_CompressedAMBank::MAX_NROAD=300000;
+#ifdef ROAD_CAND_AS_VECTOR
+int const FTK_CompressedAMBank::MAX_ROADCAND=300000;
+#endif
 
 int const FTK_CompressedAMBank::s_WILDCARDid=-1;
 int const FTK_CompressedAMBank::s_INVALIDid=-2;
@@ -71,43 +74,6 @@ static int g_event=0;
 
 //using namespace std;
 
-template<class A> inline void FTK_CompressedAMBank::patternLoop
-(A &a,uint8_t const * __restrict ptr,uint32_t firstPattern,int nPattern)
-   const {
-   // first pattern ID is known
-   a.initialize(firstPattern);
-   a.process();
-   // loop over all compressed patterns
-   for(--nPattern;nPattern>0;nPattern--) {
-      uint8_t d=*(ptr++);
-      if(d>=0xf0) {
-         // process multiple patterns with delta=1
-         int di=d-0xef;
-         nPattern-=di;
-         do {
-            a.update(1);
-            a.process();
-            di--;
-         } while(di>=0);
-      } else {
-         // process one pattern
-         uint32_t delta=1;
-         while(d & 0x80) {
-            // pattern with more than 7 bits
-            //  add non-zero high bits in groups of 4 bits
-            int shift=((d>>2)&0x3c)-25;
-            delta += ((uint32_t)(d&0xf))<<shift;
-            d=*(ptr++);
-         }
-         delta += d;
-         // process one pattern
-         a.update(delta);
-         a.process();
-      }
-   }
-   // if(nPattern<0) { std::cout<<"bug\n"; exit(0); }
-}
-
 FTK_CompressedAMBank::~FTK_CompressedAMBank() {
    if (m_TSPmap) delete m_TSPmap;
 }
@@ -116,13 +82,13 @@ FTK_CompressedAMBank::FTK_CompressedAMBank
 (int bankID,int subID,FTKSSMap *ssMap,FTKSSMap *ssMapTSP,
  int hwmodeid_TSP,int hwmodeid_DC,char const *name)
    : FTKLogging(name),FTK_AMsimulation_base(bankID,subID),
-     m_nRoadCand(0),
      m_nhWCmin(0),
      m_MAX_MISSING_PLANES(0),
      m_SSmapTSP(ssMapTSP),
      m_hwmodeIDtsp(hwmodeid_TSP),
      m_hwmodeIDdc(hwmodeid_DC),
-     m_nDCmax(-1),m_wildcardPenalty(0) {
+     m_nDCmax(-1),m_wildcardPenalty(0),
+     m_compressionScheme(FTK_CompressedAMBank::COMPRESSION_DEFAULT) {
    setSSMap(ssMap);
    if(getSSMap()&& getSSMapTSP()) {
       m_TSPmap = new TSPMap(getSSMap(),getSSMapTSP()); // TSPLevel
@@ -131,7 +97,15 @@ FTK_CompressedAMBank::FTK_CompressedAMBank
    }
    Info("CompressedAMBank")
       <<"hwmodeIDtsp="<<m_hwmodeIDtsp
-      <<" hwmodeIDdc="<<m_hwmodeIDdc<<"\n";
+      <<" hwmodeIDdc="<<m_hwmodeIDdc
+      <<" initial compressionScheme="<<m_compressionScheme
+      <<"\n";
+}
+
+void FTK_CompressedAMBank::setCompressionScheme(int scheme) {
+   m_compressionScheme=scheme;
+   Info("setCompressionScheme")
+      <<"scheme for next bank import is "<<getCompressionScheme()<<"\n"; 
 }
 
 void FTK_CompressedAMBank::setNDCmax(int ndc) {
@@ -201,7 +175,6 @@ void FTK_CompressedAMBank::setNPlanes(int nPlanes) {
    m_badModules.resize(getNPlanes());
 
    // set up lookup-tables to convert compressed DC bits to subSSmask,DC,HB
-   m_subSSmask.resize(getNPlanes());
    m_dcMaskLookup.resize(getNPlanes());
    m_hbMaskLookup.resize(getNPlanes());
    for(int ipl=0;ipl<getNPlanes();ipl++) {
@@ -211,7 +184,6 @@ void FTK_CompressedAMBank::setNPlanes(int nPlanes) {
          nBitsY=m_TSPmap->getNBits(ipl,1);
       }
       unsigned n2= 1<<(2*(nBitsX+nBitsY));
-      m_subSSmask[ipl].resize(n2);
       m_dcMaskLookup[ipl].resize(n2);
       m_hbMaskLookup[ipl].resize(n2);
       unsigned nPosX=1<<nBitsX;
@@ -236,7 +208,6 @@ void FTK_CompressedAMBank::setNPlanes(int nPlanes) {
                subMaskOr <<=1;
             }
          }
-         m_subSSmask[ipl][xy]=subMask;
          m_dcMaskLookup[ipl][xy]=dcx | (dcy<<nBitsX);
          m_hbMaskLookup[ipl][xy]=hbx | (hby<<nBitsY);
       }
@@ -485,29 +456,31 @@ int FTK_CompressedAMBank::writePCachedBankFile
    }
    // patternID counter, required for writing special patterns
    int patternID=0;
-   // loop over sectors
+   // loop over sectors, order by first pattern
+   MAP<int,size_t> sectorByPatternID;
+   for(size_t sector=0;sector<m_bank.m_PatternRangeBySector.size();sector++) {
+      Range const &range=m_bank.m_PatternRangeBySector[sector];
+      // skip empty sectors
+      if(!range.Size()) continue;
+      sectorByPatternID[range.First()]=sector;
+   }
    int isub=getSubID();
-   MAP<int,int> sectorByPatternID;
    VECTOR<int> sectorWritten;
-   for(MAP<int,std::pair<int,int> >::const_iterator isector=
-          m_SectorFirstLastPattern.begin();
-       isector!=m_SectorFirstLastPattern.end();isector++) {
-      sectorByPatternID[(*isector).second.first]=(*isector).first;
-   }
-   for(MAP<int,int>::const_iterator iSector=sectorByPatternID.begin();
-       iSector!=sectorByPatternID.end();iSector++) {
-      int sector=(*iSector).second;
-      if(nsub && (!flatFormat) &&((sector %nsub)!=isub)) continue;
-      if(!((sector-isub)%100)) {
+   for(MAP<int,size_t>::const_iterator ptr=sectorByPatternID.begin();
+       ptr!=sectorByPatternID.end();ptr++) {
+      size_t sector=(*ptr).second;
+      Range const &range=m_bank.m_PatternRangeBySector[sector];
+      // skip empty sectors -- not needed
+      //    if(!range.Size()) continue;
+      sectorID=sector;
+      if(nsub && (!flatFormat) &&((sectorID %nsub)!=isub)) continue;
+      if(!((sectorID-isub)%100)) {
          Info("writePCachedBankFile")<<"sector="<<sector<<"\n";
       }
       sectorWritten.push_back(sector);
-      MAP<int,std::pair<int,int>>::const_iterator isector=
-         m_SectorFirstLastPattern.find(sector);
-      int firstPattern=(*isector).second.first;
-      int lastPattern=(*isector).second.second;
+      int firstPattern=range.First();
+      int lastPattern=range.Last();
       // loop over all patterns in the sector
-      sectorID=sector;
       for(int ipattern=firstPattern;ipattern<=lastPattern;ipattern++) {
          // skip over reserved patterns (HW compatibility)
          if(isReservedPatternId(ipattern)) continue;
@@ -549,25 +522,14 @@ int FTK_CompressedAMBank::writePCachedBankFile
          for (int ipl=getNPlanes()-1;ipl>=0;--ipl) {
             // number of DC bits in this plane
             int nDCbits=m_TSPmap->getNBits(ipl);
-            // number of DC+HB bits in this plane
-            int nDCHBbits=2*nDCbits;
-            unsigned dcSSID_with_DCbits;
-            if(m_bank.m_pattern8Data[ipl].size()) {
-               dcSSID_with_DCbits=m_bank.m_pattern8Data[ipl][ipattern];
-            } else {
-               dcSSID_with_DCbits=m_bank.m_pattern16Data[ipl][ipattern];
-            }
-            // SSID index is encoded in the upper bits
-            int dcSSIDindex=dcSSID_with_DCbits >> nDCHBbits;
             // SSID index is converted to SSID using lookup-table
-            int dcSSID=m_bank.m_PatternByLayer[ipl].m_dcSSIDbySectorIndex
-               [sector][dcSSIDindex];
-            // DC and HB bits are encoded in the lower bits
-            int dcBits=dcSSID_with_DCbits & ((1<<nDCHBbits)-1);
-            // use lookup-table to translate and add these bits to the
-            //  DC,HB words
-            dcmask =(dcmask<<nDCbits) | m_dcMaskLookup[ipl][dcBits];
-            hbmask =(hbmask<<nDCbits) | m_hbMaskLookup[ipl][dcBits];
+            int dcSSID=m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+               getSSID(sector,ipattern);
+            std::pair<uint16_t,uint16_t> dchb=
+               m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+               getDCHB(ipattern);
+            hbmask = (hbmask<<nDCbits)|dchb.second;
+            dcmask = (dcmask<<nDCbits)|dchb.first;
             // set SSID
             if(flatFormat) {
                ssid[ipl]=dcSSID;
@@ -604,7 +566,7 @@ int FTK_CompressedAMBank::writePCachedBankFile
       unsigned int ndc[8]; // number of DC bits per plane
       unsigned int wildcard;
       //unsigned lowestSSID;
-      int sector,firstPattern,lastPattern,isub,lamb;
+      int sector,firstPattern,lastPattern,isub,lamb,allPatternsUsed;
       auxtree->Branch("nplanes",&nplanes,"nplanes/I");
       auxtree->Branch("ndc",ndc,"ndc[nplanes]/I");
       auxtree->Branch("sector",&sector,"sector/I");
@@ -613,6 +575,7 @@ int FTK_CompressedAMBank::writePCachedBankFile
       auxtree->Branch("lamb",&lamb,"lamb/I");
       auxtree->Branch("isub",&isub,"isub/I");
       auxtree->Branch("wildcard",&wildcard,"wildcard/I");
+      auxtree->Branch("allPatternsUsed",&allPatternsUsed,"allPatternsUsed/I");
       //auxtree->Branch("lowestSSID",&lowestSSID,"lowestSSID/I");
       // set number of DC bits per plane (constant)
       for(int i=0;i<getNPlanes();i++) {
@@ -620,14 +583,17 @@ int FTK_CompressedAMBank::writePCachedBankFile
       }
       for(size_t i=0;i<sectorWritten.size();i++) {
          sector=sectorWritten[i];
-         MAP<int,std::pair<int,int> >::const_iterator isector=
-            m_SectorFirstLastPattern.find(sector);
-         firstPattern=(*isector).second.first;
-         lastPattern=(*isector).second.second;
+         Range const &range=m_bank.m_PatternRangeBySector[sector];
+         firstPattern=range.First();
+         lastPattern=range.Last();
          isub= nsub ? (sector % nsub) : 0;
          lamb= nlamb ? (sector % nlamb) : 0;
          wildcard=m_SectorWC[sector];
-         //lowestSSID=;
+         MAP<int,bool>::const_iterator tooFew=m_tooFew.find(sector);
+         allPatternsUsed=-1;
+         if(tooFew!=m_tooFew.end()) {
+            allPatternsUsed=(*tooFew).second ? 1 : 0;
+         }
          auxtree->Fill();
       }
       auxtree->Write("", TObject::kOverwrite);
@@ -703,11 +669,11 @@ int FTK_CompressedAMBank::getHWModeSS_tsp(void) const {
    the SSIDs are buffered in a map for efficient retreival
  */
 std::pair<int,int> const &FTK_CompressedAMBank::getDCssid
-(int layer,int sector,int tspSSID) {
+(int layer,int tspSSID) {
    MAP<int,std::pair<int,int> >::const_iterator
       i=m_TSPtoDC[layer].find(tspSSID);
    if(i==m_TSPtoDC[layer].end()) {
-      insertSSID(layer,sector,tspSSID,s_WILDCARDid);
+      insertSSID(layer,tspSSID,s_WILDCARDid);
       i=m_TSPtoDC[layer].find(tspSSID);
    }   
    return (*i).second;
@@ -730,11 +696,11 @@ int FTK_CompressedAMBank::getDCssidConst
    the SSIDs are buffered in a map for efficient retreival
  */
 std::vector<int> const &FTK_CompressedAMBank::getTSPssidVector
-(int layer,int sector,int dcSSID) {
+(int layer,int dcSSID) {
    MAP<int,std::vector<int> >::const_iterator
       i=m_DCtoTSP[layer].find(dcSSID);
    if(i==m_DCtoTSP[layer].end()) {
-      insertSSID(layer,sector,s_WILDCARDid,dcSSID);
+      insertSSID(layer,s_WILDCARDid,dcSSID);
       i=m_DCtoTSP[layer].find(dcSSID);
    }   
    return (*i).second;
@@ -746,7 +712,7 @@ std::vector<int> const &FTK_CompressedAMBank::getTSPssidVector
  */
 
 int FTK_CompressedAMBank::getDCssidSlow
-(int layer,int sector,int tspSSID,int *moduleID) {
+(int layer,int tspSSID,int *moduleID) {
    int dcSSID=-1;
    int nDim=m_TSPmap->getDim(layer);
    if (FTKSetup::getFTKSetup().getSectorsAsPatterns()) {
@@ -799,19 +765,7 @@ int FTK_CompressedAMBank::getDCssidSlow
       }
       if (getHWModeSS_dc()==0) {
          if(phimod<0) {
-            if(m_moduleIdHW0.size()) {
-               static FTKHit hit;
-               hit.setSector(m_moduleIdHW0[layer][sector]);
-               phimod=hit.getPhiModule();
-               section=hit.getSection();
-               if((nDim==2)&& !hit.getIsBarrel()) {
-                  etacode=14+3*(hit.getASide() ? 1 : 0)+section;
-               } else {
-                  etacode=hit.getEtaCode();
-               }
-            } else {
-               Fatal("getDCssidSlow")<<"no lookup-table to convert HWMODEID=2 to HWMODEID=0\n";
-            }
+            Fatal("getDCssidSlow")<<"no lookup-table to convert HWMODEID=2 to HWMODEID=0\n";
          }
          if (nDim==2) {
             dcSSID=getSSMap()->getSSxy
@@ -822,23 +776,7 @@ int FTK_CompressedAMBank::getDCssidSlow
          }
       } else if(getHWModeSS_dc()==2) {
          if(localModuleID<0) {
-            if(m_moduleIdHW2.size()) {
-               int moduleID=m_moduleIdHW2[layer][sector];
-               localModuleID=getSSMapTSP()->getRegionMap()
-                  ->getLocalId(getBankID(),layer,moduleID);
-               if(localModuleID<0) {
-                  Fatal("getDCssidSlow")
-                     <<"plane="<<layer
-                     <<" sector="<<sector
-                     <<" phimod="<<phimod
-                     <<" etacode="<<etacode
-                     <<" section="<<section
-                     <<" moduleID="<<moduleID
-                     <<" localModuleID="<<localModuleID<<"\n";
-               }
-            } else {
-               Fatal("getDCssidSlow")<<"no lookup-table to convert HWMODEID=0 to HWMODEID=2\n";
-            }
+            Fatal("getDCssidSlow")<<"no lookup-table to convert HWMODEID=0 to HWMODEID=2\n";
          }
          if (nDim==2) {
 #ifdef HW2_USE_TSPMAP
@@ -903,7 +841,7 @@ int FTK_CompressedAMBank::getDCssidSlow
    to a tspSSID (fine geometry)
  */
 int FTK_CompressedAMBank::getTSPssidSlow
-(int layer,int sector,int dcSSID,int tspXY /* ,int *moduleID */) {
+(int layer,int dcSSID,int tspXY /* ,int *moduleID */) {
    int tspSSID=-1;
    int nDim=m_TSPmap->getDim(layer);
    int phissTSP =  getSSMapTSP()->getMap(layer, 0, 0).m_phiss;
@@ -986,28 +924,7 @@ int FTK_CompressedAMBank::getTSPssidSlow
       }
       if (getHWModeSS_tsp()==0) {
          if(phimod<0) {
-           if(m_moduleIdHW0.size()) {
-              static FTKHit hit;
-              hit.setSector(m_moduleIdHW0[layer][sector]);
-              phimod=hit.getPhiModule();
-              section=hit.getSection();
-              if((nDim==2)&& !hit.getIsBarrel()) {
-                 etacode=14+3*(hit.getASide() ? 1 : 0)+section;
-              } else {
-                 etacode=hit.getEtaCode();
-              }
-#ifdef TESTDCSSID
-              if(dcSSID==TESTDCSSID) {
-                 std::cout<<" DC->TSP dc="<<dcSSID<<" tsp="<<tspSSID
-                          <<" module(HW0)="<<m_moduleIdHW0[layer][sector]
-                          <<" module(HW2)="<<m_moduleIdHW2[layer][sector]
-                          <<" phimod="<<phimod<<" secion="<<section
-                          <<" etacode="<<etacode<<"\n";
-              }
-#endif
-            } else {
-               Fatal("getTSPssidSlow")<<"no lookup-table to convert HWMODEID=2 to HWMODEID=0\n";
-            }
+            Fatal("getTSPssidSlow")<<"no lookup-table to convert HWMODEID=2 to HWMODEID=0\n";
          }
          if (nDim==2) {
             tspSSID=getSSMapTSP()->getSSxy(layer,section,phimod,etacode,
@@ -1018,23 +935,7 @@ int FTK_CompressedAMBank::getTSPssidSlow
          }
       } else if(getHWModeSS_tsp()==2) {
          if(localModuleID<0) {
-            if(m_moduleIdHW2.size()) {
-               int moduleID=m_moduleIdHW2[layer][sector];
-               localModuleID=getSSMapTSP()->getRegionMap()
-                  ->getLocalId(getBankID(),layer,moduleID);
-               if(localModuleID<0) {
-                  Fatal("getTSPssidSlow")
-                     <<"plane="<<layer
-                     <<" sector="<<sector
-                     <<" phimod="<<phimod
-                     <<" etacode="<<etacode
-                     <<" section="<<section
-                     <<" moduleID="<<moduleID
-                     <<" localModuleID="<<localModuleID<<"\n";
-               }
-            } else {
-               Fatal("getTSPssidSlow")<<"no lookup-table to convert HWMODEID=0 to HWMODEID=2\n";
-            }
+            Fatal("getTSPssidSlow")<<"no lookup-table to convert HWMODEID=0 to HWMODEID=2\n";
          }
          if (nDim==2) {
             tspSSID=getSSMapTSP()->
@@ -1064,12 +965,12 @@ int FTK_CompressedAMBank::getTSPssidSlow
    results are buffered in lookup-tables
  */
 void FTK_CompressedAMBank::insertSSID
-(int layer,int sector,int tspSSID,int dcSSID0) {
+(int layer,int tspSSID,int dcSSID0) {
    if(!m_TSPmap) {
       m_TSPmap = new TSPMap(getSSMap(),getSSMapTSP()); // TSPLevel
    }
    // here:
-   //  (a) (tspSSID==s_INVALIDid)||(dcSSID0==s_INVALIDid)
+   //  (a) (tspSSID==s_INVALIDid)||(dcSSID0==k_INVALIDid)
    //   -> lookup requested for a bad module, no wildcard
    //  (b) (tspSSID==s_WILDCARDid)&&(dcSSID0==s_WILDCARDid)
    //   -> lookup requested for a bad module, with wildcard
@@ -1081,13 +982,13 @@ void FTK_CompressedAMBank::insertSSID
    if(tspSSID!=s_WILDCARDid) {
       // (a) or (c)
       if(tspSSID!=s_INVALIDid) {
-         dcSSID=getDCssidSlow(layer,sector,tspSSID,0);
+         dcSSID=getDCssidSlow(layer,tspSSID,0);
       } else {
          dcSSID=s_INVALIDid;
       }
    }
    // at this point:
-   //  (a1) tspSSID==s_INVALIDid  && dcSSID==s_INVALIDid
+   //  (a1) tspSSID==s_INVALIDid  && dcSSID==k_INVALIDid
    //  (a2) tspSSID==s_WILDCARDid  && dcSSID==s_INVALIDid
    //  (b)  tspSSID==s_WILDCARDid && dcSSID==s_WILDCARDid
    //  (c1) tspSSID=={valid} && dcSSID={valid}
@@ -1105,7 +1006,7 @@ void FTK_CompressedAMBank::insertSSID
    for(int iTSP=0;iTSP<nPos;iTSP++) {
       if((dcSSID!=s_INVALIDid)&&(dcSSID!=s_WILDCARDid)) {
          // (c1) or (c2)
-         tsp[iTSP]=getTSPssidSlow(layer,sector,dcSSID,iTSP);
+         tsp[iTSP]=getTSPssidSlow(layer,dcSSID,iTSP);
       } else {
          // (a1) or (a2) or (b)
          // copy DC-id which is set properly,
@@ -1119,15 +1020,15 @@ void FTK_CompressedAMBank::insertSSID
    }
    int moduleID=-1;
    if((tspSSID!=s_WILDCARDid)&&(tspSSID!=s_INVALIDid)) {
-      int dcSSID1=getDCssidSlow(layer,sector,tspSSID,&moduleID);
+      int dcSSID1=getDCssidSlow(layer,tspSSID,&moduleID);
       if((!match)||(dcSSID1!=dcSSID)) {
          std::ostream &fatal=Fatal("insertSSID");
          fatal<<"SSID inconsistency: layer="<<layer
-              <<" sector="<<sector<<" TSP0="<<tspSSID
+              <<" TSP0="<<tspSSID
               <<" (DC="<<dcSSID1<<")"
               <<" DC="<<dcSSID<<" TSP=[";
          for(int i=0;i<nPos;i++) {
-            fatal<<" "<<tsp[i]<<" (DC="<<getDCssidSlow(layer,sector,tsp[i],0)<<")";
+            fatal<<" "<<tsp[i]<<" (DC="<<getDCssidSlow(layer,tsp[i],0)<<")";
          }
          fatal<<"]\n";
       }
@@ -1307,10 +1208,19 @@ int FTK_CompressedAMBank::readPCachedBank(TDirectory *inputDir,int nlamb) {
       for(int iPattern=0;iPattern<nPattern;++iPattern) {
          // get sector number
          branch_sectorID->GetEntry(iPattern);
+         if(pattern) {
+            sectorID=pattern->getSectorID();
+         }
+         int &pos=sectorPointer[sectorID].second;
          if(!pattern) {
             // flat file
             // determine position in ssidData array
-            int &pos=sectorPointer[sectorID].second;
+            if(pos>=offsetSSID*nPattern) {
+               Fatal("readPCachedBank")
+                  <<"overflow sector="<<pattern->getSectorID()
+                  <<" pos="<<pos<<" ipattern="<<iPattern
+                  <<"\n";
+            }
             branch_ssid->SetAddress( ssidData+pos);
             pos+=nplanes;
             // here pos points to ssid address+nlayer -> DC bits
@@ -1337,12 +1247,17 @@ int FTK_CompressedAMBank::readPCachedBank(TDirectory *inputDir,int nlamb) {
          //                   -> copy to the desired location
          if(pattern) {
             if(!(iPattern %1000000))
-               Debug("readPCachedBank")
+               Info("readPCachedBank")
                   <<iPattern<<" sector="<<pattern->getSectorID()<<"\n";
             // NOTE: pos is a reference, so increasing pos (below)
             //   automatically selects the proper position for reading
             //   the next pattern in this sector
-            int &pos=sectorPointer[pattern->getSectorID()].second;
+            if(pos>=offsetSSID*nPattern) {
+               Fatal("readPCachedBank")
+                  <<"overflow sector="<<pattern->getSectorID()
+                  <<" pos="<<pos<<" ipattern="<<iPattern
+                  <<"\n";
+            }
             for(int i=0;i<nLayer;i++) {
                // SSID layer 0..N-1
                ssidData[pos++]=pattern->getSSID(i);
@@ -1350,6 +1265,14 @@ int FTK_CompressedAMBank::readPCachedBank(TDirectory *inputDir,int nlamb) {
             ssidData[pos++]=pattern->getDCMask();
             ssidData[pos++]=pattern->getHBMask();
          }
+         // skip invalid pattern
+         int nValid=0;
+         for(int i=0;i<nLayer;i++) {
+            if(ssidData[pos+i-offsetSSID]!=s_WILDCARDid) nValid++;
+         }
+         if(!nValid) {
+            pos -= offsetSSID;
+         }
       }
       if(pattern) delete pattern;
    } else {
@@ -1359,6 +1282,7 @@ int FTK_CompressedAMBank::readPCachedBank(TDirectory *inputDir,int nlamb) {
       error=-2;
    }
    if(ssidData) {
+      Info("readPCachedBank")<<"importing patterns\n";
       importDCpatterns(nLayer,offsetSSID,ssidData,sectorPointer,nlamb);
       delete [] ssidData;
    }
@@ -1424,34 +1348,57 @@ void FTK_CompressedAMBank::importDCpatterns
    }
    uint32_t ipattSector=0;
    // set number of layers
+   m_bank.m_PatternByLayer.resize(0);
    m_bank.m_PatternByLayer.resize(nLayer);
-   for(int iLayer=0;iLayer<nLayer;iLayer++) {
-      // resize to the maximum sector ID
-      m_bank.m_PatternByLayer[iLayer].
-         m_CompressedDeltaBySector.resize(sectorPointer.size());
+
+   int nPatternEstimate=0;
+   for(size_t sector=0;sector<sectorPointer.size();sector++) {
+      int nPattern=(sectorPointer[sector].second-
+                    sectorPointer[sector].first)/offsetSSID;
+      nPatternEstimate += nPattern;
    }
+   nPatternEstimate=(nPatternEstimate + (nPatternEstimate>>17) ) & 0xfffe0000;
+   m_bank.m_numTSP.reserve(nPatternEstimate);
+   m_bank.m_coverage.reserve(nPatternEstimate);
+
    // subregion (LAMB) loop
-   if(nlamb<=0) nlamb=1;
+   if(nlamb<=0) {
+      // 2^17 per AM chip
+      // 2^4 AM chips per LAMB 
+      // 4 LAMB per AUX
+      int nAUX=(nPatternEstimate+(1<<(17+4+2))-1)>>(17+4+2);
+      nlamb=nAUX<<2;
+      Info("importDCpatterns")
+         <<"nPattern= "<<nPatternEstimate
+         <<" nAUX="<<nAUX<<", setting n(LAMB) to "<<nlamb<<"\n";
+   }
    for(int ilamb=0;ilamb<nlamb;ilamb++) {
-      //
-      // sector loop
+      Info("importDCpatterns")<<"LAMB="<<ilamb<<"\n";
+      // sector loop starts here
       unsigned max_sectorByNlamb=(sectorPointer.size()-1)/nlamb;
       unsigned top_sectorByNlamb=0;
       while(top_sectorByNlamb+1 <= max_sectorByNlamb)
          top_sectorByNlamb=(top_sectorByNlamb+1)*2-1;
-      // here: top_sectorByLamb has all bits set to one and is larger or equal the largest sector/nlamb
+      // here: top_sectorByLamb has all bits set to one
+      //   and is larger or equal the largest sector/nlamb
       unsigned leadingBitMask=(top_sectorByNlamb>>1)+1;
+
+
+      // in the following loop over sectors, the variables are:
+      //     sectorByLamb : sector number/nlamb
+      //     sector : sector number
+      //     count : counter
+      //  sectorByLamb has the bit-order reversed as compared to count
       unsigned sectorByLamb=0;
-      while(true) {
-         //for(unsigned sector=ilamb;sector<sectorPointer.size();sector+=nlamb) {
+      for(unsigned count=0;count<=top_sectorByNlamb;count++) {
          unsigned sector=sectorByLamb*nlamb+ilamb;
-
          // count sectorByLamb from zero to top_sectorByNlamb
          // bits are counted in reverse order: MSB first, then next, etc:
          //  e.g. if top_sectorByNlamb has 12 bit:
-         //   0x000, 0x800, 0x400, 0xc00, 0x200, 0xa00, 0x600, 0xe00, 0x100, ... 0xfff
-         // This randomizes the sector ordering, for better load-balancing of patterns
-         // in the hardware
+         //   0x000, 0x800, 0x400, 0xc00, 0x200, 0xa00,
+         //     0x600, 0xe00, 0x100, ... 0xfff
+         // This randomizes the sector ordering, for better
+         //   load-balancing of patterns in the hardware
          for(unsigned mask=leadingBitMask;mask;mask>>=1) {
             // count the bit indicated in "mask"
             sectorByLamb^=mask;
@@ -1459,15 +1406,18 @@ void FTK_CompressedAMBank::importDCpatterns
             if(sectorByLamb & mask) break;
             // if the bit is zero, have to count the next bit
          }
-         if(!sectorByLamb) break; // all bits were counted, stop
-         // when counting in reverse bit order, sectors are not produced in sequence
-         // high (invalid) sector numbers are produced in random order and have
+         // when counting in reverse bit order, sectors are not produced
+         //  in their natural sequence
+         // high (invalid) sector numbers appear in random order and have
          // to be skipped
-         if(sector>=sectorPointer.size()) continue; // skip sector numbers outside range
+
+         // skip sector numbers outside range
+         if(sector>=sectorPointer.size()) continue;
+
          int nPattern=(sectorPointer[sector].second-
                        sectorPointer[sector].first)/offsetSSID;
          if(!nPattern) continue;
-         // sort patterns in each sector
+         // sort patterns in this sector
 #ifdef QSORT_FOR_DC_IMPORT
          int *patternDataSectorNC=ssidData+sectorPointer[sector].first;
          qsort(patternDataSectorNC,nPattern,sizeof(int)*offsetSSID,
@@ -1476,51 +1426,30 @@ void FTK_CompressedAMBank::importDCpatterns
 #else
          int const *patternDataSector(ssidData+sectorPointer[sector].first);
 #endif
-         // 
-         // loop two times over all patterns in this sector
-         //  first loop: count patterns
-         //  second loop: allocate memory and store patterns
-         uint32_t ipatt;
          //
-         struct CompressionHelper {
-            //
-            // previous pattern ID (to determine delta)
-            uint32_t m_lastPattern;
+         // loop over layers
+         // inside, loop over patterns
+         // at the end of the loop, ipatt points to
+         //   the first unused pattern number
+         uint32_t ipatt=ipattSector;
+         int layerShift=0;
+         for(int iLayer=0;iLayer<nLayer;iLayer++) {
+            // save compressed delta data in temporary structure
+            MAP<int,std::set<uint32_t> > patternSetBySSID;
             //
-            // current position when storing compressed data
-            uint32_t m_position;
+            // ternary bit decoding information
+            int nBitsX=m_TSPmap->getNBits(iLayer,0);
+            int nBitsY=0;
+            int ndim=m_TSPmap->getDim(iLayer);
+            if(ndim!=1) {
+               nBitsY=m_TSPmap->getNBits(iLayer,1);
+            }
+            int maskX=(1<<nBitsX)-1;
+            int maskY=(1<<nBitsY)-1;
             //
-            // for compression: delta and repetition count
-            uint32_t m_repeatDelta1;
-         };
-         //
-         // adress auxillary information by layer and SSID
-         std::vector<MAP<int,CompressionHelper> > compressionHelper(nLayer);
-         for(int iLoop=0;iLoop<2;iLoop++) {
+            // first pattern this sector
             ipatt=ipattSector;
-            if(iLoop) {
-               // allocate memory (second loop only)
-               for(unsigned iLayer=0;iLayer<compressionHelper.size();iLayer++) {
-                  MAP<int,CompressionHelper>
-                     &helperThisLayer=compressionHelper[iLayer];
-                  uint32_t nByte=0;
-                  for(MAP<int,CompressionHelper>::const_iterator ssid=
-                         helperThisLayer.begin();ssid!=helperThisLayer.end();
-                      ssid++) {
-                     PatternBySector_t &sectorList
-                        (m_bank.m_PatternByLayer[iLayer].
-                         m_SSidData[(*ssid).first]);
-                     PatternBySector_t::iterator dataPtr=
-                        sectorList.find(sector);
-                     SectorData &data=(*dataPtr).second;
-                     data.m_offset=nByte;
-                     data.m_length=(*ssid).second.m_position;
-                     nByte+=data.m_length; 
-                  }
-                  m_bank.m_PatternByLayer[iLayer].
-                     m_CompressedDeltaBySector[sector].resize(nByte);
-               }
-            }
+            // 
             // loop over all patterns in this sector
             for(int iPattern=0;iPattern<nPattern;iPattern++) {
                // reserve special pattern IDs as required by hardware
@@ -1531,177 +1460,94 @@ void FTK_CompressedAMBank::importDCpatterns
                   ipatt++;
                }
                int const *patternData=patternDataSector+iPattern*offsetSSID;
-               // skip pattern if all IDs are invalid
-               size_t invalid=0;
-               for(unsigned iLayer=0;iLayer<compressionHelper.size();iLayer++) {
-                  if((patternData[iLayer]==s_WILDCARDid)||
-                     (patternData[iLayer]==s_INVALIDid)) invalid++;
+               // skip this pattern if all IDs are invalid
+               int invalid=0;
+               for(int jLayer=0;jLayer<nLayer;jLayer++){
+                  if((patternData[jLayer]==s_WILDCARDid)||
+                     (patternData[jLayer]==s_INVALIDid)) invalid++;
                }
-               if(invalid==compressionHelper.size()) continue;
-
+               if(invalid==nLayer) continue;
+               // decode SSIDs
+               // a single DC pattern may expand into several TSPssids
                // DC information for this pattern
-               uint32_t dcMaskAll=patternData[nLayer];
-               uint32_t hbMaskAll=patternData[nLayer+1];
-               //
-               // loop over all planes
-               for(int iLayer=0;iLayer<nLayer;iLayer++) {
-                  MAP<int,CompressionHelper>
-                     &helperThisLayer=compressionHelper[iLayer];
-                  uint8_t *compressedDelta=m_bank.m_PatternByLayer[iLayer].
-                     m_CompressedDeltaBySector[sector].data();
-                  //  decode DC information
-                  int nBitsX=m_TSPmap->getNBits(iLayer,0);
-                  int nBitsY=0;
-                  int ndim=m_TSPmap->getDim(iLayer);
-                  if(ndim!=1) {
-                     nBitsY=m_TSPmap->getNBits(iLayer,1);
-                  }
-                  int maskX=(1<<nBitsX)-1;
-                  int maskY=(1<<nBitsY)-1;
-                  int dcx=dcMaskAll & maskX;
-                  dcMaskAll>>=nBitsX;
-                  int dcy=dcMaskAll & maskY;
-                  dcMaskAll>>=nBitsY;
-                  int hbx=hbMaskAll & maskX;
-                  hbMaskAll>>=nBitsX;
-                  int hby=hbMaskAll & maskY;
-                  hbMaskAll>>=nBitsY;
-                  int dchb=(((((dcy<<nBitsY)|hby)<<nBitsX)|dcx)<<nBitsX)|hbx;
-                  // expand DC bits to the list of valid subSS indexes
-                  std::vector<int> const &tspIndexes=
-                     xyFromHBDCandLayer[iLayer][dchb];
-                  int ssid=patternData[iLayer];
-                  // loop over subSS indexes within dcSSID
-                  int numTSP=tspIndexes.size();
-                  if((ssid==s_WILDCARDid)||(ssid==s_INVALIDid)) {
-                     // wildcard/invalid pattern has no DC bits
-                     // -> only one TSP pattern
-                     numTSP=1;
-                  }
-                  for(int iTSP=0;iTSP<numTSP;iTSP++) {
-                     // calculate TSP pattern address
-                     uint32_t tspid=getTSPssid
-                        (iLayer,sector,ssid,tspIndexes[iTSP]);
-                     // find auxillary information
-                     CompressionHelper &helper=helperThisLayer[tspid];
-                     // find target section of the pattern bank
-                     PatternBySector_t &sectorList
-                        (m_bank.m_PatternByLayer[iLayer].m_SSidData[tspid]);
-                     PatternBySector_t::iterator dataPtr=
-                        sectorList.find(sector);
-                     if(dataPtr==sectorList.end()) {
-                        // first look, first pattern
-                        // initialize data structure
-                        SectorData &data=sectorList[sector];
-                        // first pattern in this bank section, reset members
-                        // store pattern ID
-                        data.m_FirstPattern=ipatt;
-                        // reset pattern counter
-                        data.m_NPattern=1;
-                        // reset compressed data counter
-                        helper.m_position=0;
-                        helper.m_repeatDelta1=0;
-                     } else {
-                        SectorData &data=(*dataPtr).second;
-                        if(ipatt==data.m_FirstPattern) {
-                           // second loop, first pattern
-                           // reset pattern counter
-                           data.m_NPattern=1;
-                           // reset position and count of repeated deltas
-                           helper.m_position=0;
-                           helper.m_repeatDelta1=0;
-                        } else {
-                           // calculate delta to previous pattern 
-                           uint32_t delta=ipatt-helper.m_lastPattern-1;
-                           // number of bytes needed to store this delta
-                           uint32_t &pos=helper.m_position;
-                           uint32_t mask4=0x780;
-                           int shift=7;
-                           // check whether some bits >=7 are nonzero
-                           //  -> need extra bytes to store this delta
-                           for(uint32_t mask=0xffffff80;mask;mask<<=4) {
-                              if((delta & mask)==0) break;
-                              uint32_t bits=delta & mask4;
-                              if(bits) {
-                                 if(iLoop) {
-                                    compressedDelta[data.m_offset+pos]=
-                                       (bits>>shift)|((shift+25)<<2);
-                                 }
-                                 pos++;
-                              }
-                              mask4 <<=4;
-                              shift+=4;
-                           }
-                           // count number of patterns
-                           data.m_NPattern++;
-                           // count number of data bytes needed
-                           if(!delta) {
-                              if((helper.m_repeatDelta1<1)||
-                                 (helper.m_repeatDelta1>=16)) {
-                                 helper.m_repeatDelta1=1;
-                                 if(iLoop) {
-                                    compressedDelta[data.m_offset+pos]=0;
-                                 }
-                                 pos++;
-                              } else {
-                                 helper.m_repeatDelta1++;
-                                 if(iLoop) {
-                                    compressedDelta[data.m_offset+pos-1]=
-                                       helper.m_repeatDelta1 + 0xee;
-                                 }
-                              }
-                           } else {
-                              helper.m_repeatDelta1=0;
-                              if(iLoop) {
-                                 compressedDelta[data.m_offset+pos]=
-                                    delta & 0x7f;
-                              }
-                              pos++;
-                           }
-                        }
-                     }
-                     helper.m_lastPattern=ipatt;
-                  }
+               uint32_t dcMaskLayer=patternData[nLayer]>>layerShift;
+               uint32_t hbMaskLayer=patternData[nLayer+1]>>layerShift;
+               //  decode DC information
+               int dcx=dcMaskLayer & maskX;
+               dcMaskLayer>>=nBitsX;
+               int dcy=dcMaskLayer & maskY;
+               int hbx=hbMaskLayer & maskX;
+               hbMaskLayer>>=nBitsX;
+               int hby=hbMaskLayer & maskY;
+               int dchb=(((((dcy<<nBitsY)|hby)<<nBitsX)|dcx)<<nBitsX)|hbx;
+               // expand DC bits to the list of valid subSS indexes
+               std::vector<int> const &tspIndexes=
+                  xyFromHBDCandLayer[iLayer][dchb];
+               int ssid=patternData[iLayer];
+               // loop over subSS indexes within dcSSID
+               int numTSP=tspIndexes.size();
+               if((ssid==s_WILDCARDid)||(ssid==s_INVALIDid)) {
+                  // wildcard/invalid pattern has no DC bits
+                  // -> only one TSP pattern
+                  numTSP=1;
+               }
+               for(int iTSP=0;iTSP<numTSP;iTSP++) {
+                  // calculate TSP pattern address
+                  uint32_t tspid=getTSPssid
+                     (iLayer,ssid,tspIndexes[iTSP]);
+                  // inner loop
+                  patternSetBySSID[tspid].insert(ipatt);
                }
                ipatt++;
-            } // end loop over nPattern
-            if(iLoop) {
-               // extract auxillary information (coverage and #TSP patterns)
-               if(offsetSSID>=nLayer+4) {
-                  m_bank.m_numTSP.resize(ipatt);
-                  m_bank.m_coverage.resize(ipatt);
-                  ipatt=ipattSector;
-                  for(int iPattern=0;iPattern<nPattern;iPattern++) {
-                     if(isReservedPatternId(ipatt)) {
-                        // skip over reserved IDs
-                        ipatt++;
-                     }
-                     int const *patternData=
-                        patternDataSector+iPattern*offsetSSID;
-                     // Auxillary information for this pattern
-                      m_bank.m_numTSP[ipatt]=
-                         patternData[nLayer+2];
-                      m_bank.m_coverage[ipatt]=
-                         patternData[nLayer+3];
-                      ipatt++;
-                  }
+            }
+            // here, all SSIDs in this layer,sector have been processed
+            // transfer data from compression helper to final data vector
+            for(MAP<int,std::set<uint32_t> >::const_iterator iSSID=
+                   patternSetBySSID.begin();iSSID!=patternSetBySSID.end();
+                iSSID++) {
+               int tspid=(*iSSID).first;
+               m_bank.m_PatternByLayer[iLayer].m_SSidData[tspid].
+                  importPatternSet(sector,(*iSSID).second,
+                                   getCompressionScheme());
+            }
+
+            // update ternary bit shift for next layer
+            layerShift += nBitsX+nBitsY;
+         }
+         // extract auxillary information (coverage and #TSP patterns)
+         if(offsetSSID>=nLayer+4) {
+            m_bank.m_numTSP.resize(ipatt);
+            m_bank.m_coverage.resize(ipatt);
+            ipatt=ipattSector;
+            for(int iPattern=0;iPattern<nPattern;iPattern++) {
+               if(isReservedPatternId(ipatt)) {
+                  // skip over reserved IDs
+                  ipatt++;
                }
+               int const *patternData=
+                  patternDataSector+iPattern*offsetSSID;
+               // Auxillary information for this pattern
+               m_bank.m_numTSP[ipatt]=
+                  patternData[nLayer+2];
+               m_bank.m_coverage[ipatt]=
+                  patternData[nLayer+3];
+               ipatt++;
             }
          }
+         // update pattern number for next sector
          ipattSector=ipatt;
          if((!(sector%100))||
             (sector<10)||((sector<100)&&(!(sector%10)))) {
             Debug("importDCpatterns")
                <<"sector "<<sector<<" nPatt="<<ipatt<<"\n";
          }
+         if(!sectorByLamb) break; // all bits were counted, stop
       } // end loop over sectors
    } // end loop over subregions
 }
 
 void FTK_CompressedAMBank::erase(void) {
    m_bank.m_PatternByLayer.resize(0);
-   m_bank.m_pattern8Data.resize(0);
-   m_bank.m_pattern16Data.resize(0);
    m_bank.m_numTSP.resize(0);
    m_bank.m_coverage.resize(0);
    setNPlanes(0);
@@ -1727,10 +1573,14 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    // memory consumption (estimate)
    uint32_t memorySSIDlookup=0;
    uint32_t memoryPatternIDlookup=0;
+#ifdef SEARCH_MEMORY_LEAK
+   printVmemUsage("readBankPostprocessing start");
+#endif
 
    readWildcards();
 
-   m_SectorFirstLastPattern.clear();
+   m_bank.m_PatternRangeBySector.resize(0);
+   m_bank.m_PatternRangeBySector.reserve(16384);
 
    if(!m_TSPmap) {
       m_TSPmap = new TSPMap(getSSMap(),getSSMapTSP()); // TSPLevel
@@ -1746,25 +1596,102 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    //      index=dcSSIDBySectorLayer[layer][sector][ssid]
    //    for unpacking bank data (data member):
    //      ssid=m_bank.m_PatternByLayer[layer].m_SSidData[sector][index
-   std::vector<MAP<int,MAP<int,int> > >
-      dcSSIDBySectorLayer(m_bank.m_PatternByLayer.size());
 
    //
    // pack data into VECTORMAP structures
+
+   for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
+      LayerData &layerData=m_bank.m_PatternByLayer[layer];
+      layerData.m_SSidData.pack();
+   }
+
+   Info(where)<<"repacking pattern bank, compression scheme="
+              <<getCompressionScheme()<<"\n";
+
+   // pack and compress pattern 
+   if(getCompressionScheme()!=COMPRESSION_SKIP) {
+      for(size_t iLayer=0;iLayer<m_bank.m_PatternByLayer.size();iLayer++) {
+         for(PatternBySectorSSidMap_t::iterator iSSID=
+                m_bank.m_PatternByLayer[iLayer].m_SSidData.begin();
+             iSSID!=m_bank.m_PatternByLayer[iLayer].m_SSidData.end();iSSID++) {
+            //std::cout<<iLayer<<"/"<<(*iSSID).first<<" start size: "
+            //         <<(*iSSID).second.getMemoryEstimate()<<"\n";
+            (*iSSID).second.finalize(getCompressionScheme());
+            //std::cout<<iLayer<<"/"<<(*iSSID).first<<" end size: "
+            //         <<(*iSSID).second.getMemoryEstimate()<<"\n";
+         }
+      }
+   }
+   // report encoding schemes actually used
+   for(size_t iLayer=0;iLayer<m_bank.m_PatternByLayer.size();iLayer++) {
+      MAP<uint32_t,uint32_t> encodingScheme;
+      for(PatternBySectorSSidMap_t::const_iterator iSSID=
+             m_bank.m_PatternByLayer[iLayer].m_SSidData.begin();
+          iSSID!=m_bank.m_PatternByLayer[iLayer].m_SSidData.end();iSSID++) {
+         for(FTK_CompressedSectorPatternList::const_iterator iSector=
+                (*iSSID).second.begin();iSector!=(*iSSID).second.end();
+             iSector++) {
+            encodingScheme[(*iSector).second.getEncoding()]++;
+         }
+      }
+      std::ostream &out=(Info(where)<<"L"<<iLayer<<" encoding");
+      for(MAP<uint32_t,uint32_t>::const_iterator ienc=encodingScheme.begin();
+          ienc!=encodingScheme.end();ienc++) {
+         out<<" ["<<(*ienc).first<<"]="<<(*ienc).second;
+      }
+      out<<"\n";
+   }
+
+   // determine pattern range per sector
+   // map of DC SSID per layer and sector 
+   VECTOR<VECTOR<MAP<int,int> > >
+      encodedDCSSIDbySectorLayer(m_bank.m_PatternByLayer.size());
+
    for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
       LayerData &layerData=m_bank.m_PatternByLayer[layer];
+      VECTOR<MAP<int,int> > &encodedDCSSIDBySector=
+         encodedDCSSIDbySectorLayer[layer];
+      encodedDCSSIDBySector.reserve(16384);
       for(PatternBySectorSSidMap_t::iterator iSSID=
              layerData.m_SSidData.begin();
-          iSSID!=layerData.m_SSidData.end();iSSID++) {
-         (*iSSID).second.pack();
+          iSSID!=layerData.m_SSidData.end();++iSSID) {
+         int ssid=(*iSSID).first;
+         FTK_CompressedSectorPatternList const &patternList((*iSSID).second);
+
+         patternTSPcount[layer]+= patternList.getNPattern();
+         uint32_t maxSector=patternList.maxSector();
+         while(m_bank.m_PatternRangeBySector.size()<=maxSector) {
+            m_bank.m_PatternRangeBySector.push_back(Range());
+         }
+         if(maxSector>=encodedDCSSIDBySector.size()) {
+            encodedDCSSIDBySector.resize(maxSector+1);
+         }
+
+         int dcSSID=getDCssid(layer,ssid).first;
+
+         // determine min and max pattern id per sector
+         // initialize table of encoded DC-SSID by layer,sector,DCssid
+         Range all;
+         for(FTK_CompressedSectorPatternList::const_iterator iSector=
+                patternList.begin();iSector!=patternList.end();iSector++) { 
+            uint32_t sector=(*iSector).first;
+            FTK_CompressedPatternList const &plist=(*iSector).second;
+            Range &range(m_bank.m_PatternRangeBySector[sector]);
+            std::pair<uint32_t,uint32_t> minMax=plist.getMinMaxPattern();
+            range.UpdateRange(minMax.first,minMax.second);
+            all.UpdateRange(minMax.first,minMax.second);
+            if(encodedDCSSIDBySector[sector].find(dcSSID)==
+               encodedDCSSIDBySector[sector].end()) {
+               int n=encodedDCSSIDBySector[sector].size();
+               encodedDCSSIDBySector[sector][dcSSID]=n;
+            }
+         }
+         // determine maximum pattern number
+         if(m_npatterns<all.Last()) m_npatterns=all.Last();
       }
-      layerData.m_SSidData.pack();
    }
 
-   //
-   // table of delta data
-   std::vector<uint32_t> deltaMultiplicity(0x100);
-
+   // estimate memory consumption
    for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
       LayerData const &layerData=m_bank.m_PatternByLayer[layer];
       ssidCountTotal += layerData.m_SSidData.size();
@@ -1772,167 +1699,113 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
              layerData.m_SSidData.beginPtr();
           ssid!=layerData.m_SSidData.endPtr();++ssid) {
          sectorCountTotal += (*ssid).second.size();
-         // get DC-level SSID
-         for(PatternBySector_t::const_ptr sector=(*ssid).second.beginPtr();
-             sector!=(*ssid).second.endPtr();++sector) {
-            int sectorID=(*sector).first;
-            int dcSSID=getDCssid(layer,sectorID,(*ssid).first).first;
-            // remember DC-level SSID for this sector
-            // (insert a new entry)
-            // set index to -1 (undefined)
-            dcSSIDBySectorLayer[layer][sectorID][dcSSID]=-1;
-            // unpack bank data to determine min/max pattern ID in this
-            //  sector
-            SectorData const &sectordata=(*sector).second;
-            patternTSPcount[layer]+=sectordata.m_NPattern;
-            class GetMinMax {
-            public:
-               inline void initialize(int firstPattern) {
-                  minPatternId=firstPattern;
-                  maxPatternId=firstPattern;
-               }
-               inline void process(void) { }
-               inline void update(int delta) {
-                  maxPatternId+=delta;
-               }
-               int minPatternId,maxPatternId;
-            } getMinMax;
-            patternLoop(getMinMax,
-                        layerData.m_CompressedDeltaBySector[sectorID].data()+
-                        sectordata.m_offset,
-                        sectordata.m_FirstPattern,
-                        sectordata.m_NPattern);
-            int minPatternId=getMinMax.minPatternId;
-            int maxPatternId=getMinMax.maxPatternId;
-            if(m_npatterns<maxPatternId)
-               m_npatterns=maxPatternId;
-            MAP<int,std::pair<int,int> >::iterator is=
-               m_SectorFirstLastPattern.find(sectorID);
-            if(is==m_SectorFirstLastPattern.end()) {
-               m_SectorFirstLastPattern.insert
-                  (std::make_pair
-                   (sectorID,std::make_pair(minPatternId,maxPatternId)));
-            } else {
-               if((*is).second.first>minPatternId) 
-                  (*is).second.first=minPatternId;
-               if((*is).second.second<maxPatternId)
-                  (*is).second.second=maxPatternId;
-            }
-            // estimate memory consumption
-            memorySSIDlookup+=sizeof(uint8_t)*sectordata.m_length;
-         }
-         // memory for this SSID map
-         //   [parent, previous,next,child] plus vector [ptr,size]
          memorySSIDlookup+= (*ssid).second.getMemoryEstimate();
 
       }
       memorySSIDlookup += sizeof(LayerData)
          +layerData.m_SSidData.getMemoryEstimate();
    }
+   
    // number of patterns = maximum patternID+1
    m_npatterns++;
-   m_hitPatterns.resize(m_npatterns);
-   m_roadCand.resize(MAX_NROAD);
-   //
-#ifdef PRINT_MULTIPLICITY
-   MAP<uint64_t,int> histogram;
-   for(int i=0;i<0x100;i++) {
-      histogram[(((uint64_t)deltaMultiplicity[i])<<8)|i]=i;
-   }
-   uint32_t sum=0;
-   for(MAP<uint64_t,int>::const_iterator i=histogram.begin();
-       i!=histogram.end();i++) {
-      sum += ((*i).first>>8);
-      std::cout<<std::setbase(16)<<std::setw(3)<<(*i).second
-               <<std::setbase(10)<<std::setw(10)<<((*i).first>>8)
-               <<std::setw(10)<<sum
-               <<"\n";
-   }
+   m_hitMask.setNPattern(m_npatterns);
+#ifdef ROAD_CAND_AS_VECTOR
+   m_roadCand.resize(0);
+   m_roadCand.reserve(MAX_ROADCAND);
+#else
+   m_roadCandMap.clear();
 #endif
+   //
    // determine minimum and maximum number of patterns per sector
-   int minPattern=-1,maxPattern=-1;
-   for(MAP<int,std::pair<int,int> >::const_iterator
-          is=m_SectorFirstLastPattern.begin();
-       is!=m_SectorFirstLastPattern.end();is++) {
-      int nPattern=(*is).second.second-(*is).second.first+1;
-      if(maxPattern==-1) {
-         minPattern=nPattern;
-         maxPattern=nPattern;
-      } else {
-         if(minPattern>nPattern) minPattern=nPattern;
-         if(maxPattern<nPattern) maxPattern=nPattern;
-      }
+   Range patternsPerSector;
+   for(size_t sector=0;sector<m_bank.m_PatternRangeBySector.size();sector++) {
+      Range const &range=m_bank.m_PatternRangeBySector[sector];
+      int nPattern=range.Size();
+      if(!nPattern) continue;
+      patternsPerSector.UpdateRange(nPattern,nPattern);
    }
    // determine maximum sector ID
-   int maxSector=0;
-   if(m_SectorFirstLastPattern.rbegin()!=m_SectorFirstLastPattern.rend()) 
-      maxSector=(*m_SectorFirstLastPattern.rbegin()).first+1;
+   int maxSector=m_bank.m_PatternRangeBySector.size();
 
-   // determine number of dc-SSIDs per layer/sector
+   // store DC <-> encoded DC translation table per layer/sector
    //   and set up translation tables
-   m_bank.m_pattern8Data.resize(getNPlanes());
-   m_bank.m_pattern16Data.resize(getNPlanes());
-   for(unsigned layer=0;layer<dcSSIDBySectorLayer.size();layer++) {
-      unsigned iMax=0;
-      // layer loop
-      m_bank.m_PatternByLayer[layer].m_dcSSIDbySectorIndex.resize(maxSector);
-      for(MAP<int,MAP<int,int> >::iterator sector=
-             dcSSIDBySectorLayer[layer].begin();
-          sector!=dcSSIDBySectorLayer[layer].end();sector++) {
-         // sector loop
-         //
-         VECTOR<int> &dcSSIDtable=
-            m_bank.m_PatternByLayer[layer].m_dcSSIDbySectorIndex
-            [(*sector).first];
+   for(unsigned layer=0;layer<encodedDCSSIDbySectorLayer.size();
+       layer++) {
+      LayerData &layerData=m_bank.m_PatternByLayer[layer];
+      VECTOR<MAP<int,int> > const &encodedDCSSIDBySector=
+         encodedDCSSIDbySectorLayer[layer];
+      layerData.m_SSIDternaryByPattern.m_dcSSIDbySectorIndex.resize(maxSector);
+      uint32_t maxNDC=0;
+      //
+      // sector loop
+      for(uint32_t sector=0;sector<encodedDCSSIDBySector.size();
+          sector++) {
+         MAP<int,int> const &dcSSID(encodedDCSSIDBySector[sector]);
          //
-         // size of the table is the number of distinct SSIDs in this
-         //     layer,sector
-         dcSSIDtable.resize((*sector).second.size());
+         // number of distinct SSIDs in this layer/sector
+         size_t nDCSSID=dcSSID.size();
+         if(!nDCSSID) continue;
+         VECTOR<int> &dcSSIDtable= layerData.
+            m_SSIDternaryByPattern.m_dcSSIDbySectorIndex[sector];
+         dcSSIDtable.reserve(nDCSSID);
+         dcSSIDtable.resize(nDCSSID);
          memoryPatternIDlookup += sizeof(int)*dcSSIDtable.size();
          //
-         // assign indexes for each SSID given (layer,sector)
-         int i=0;
-         for(MAP<int,int>::iterator ssid=(*sector).second.begin();
-             ssid!=(*sector).second.end();ssid++) {
-            // set up table to encode SSID->index
-            (*ssid).second=i;
+         // copy SSID indexes to data structure
+         for(MAP<int,int>::const_iterator ssid=dcSSID.begin();
+             ssid!=dcSSID.end();ssid++) {
             // set up table to decode index->SSID
-            dcSSIDtable[i++]= (*ssid).first;
+            if(((unsigned)(*ssid).second)>=dcSSIDtable.size()) {
+               Fatal(where)<<"overflow when storing DC-SSID translation table\n";
+            }
+            dcSSIDtable[(*ssid).second]= (*ssid).first;
          }
          // maximum index in this layer
-         if(dcSSIDtable.size()>iMax) iMax=dcSSIDtable.size();
+         if(dcSSIDtable.size()>maxNDC) maxNDC=dcSSIDtable.size();
       }
       // estimate memory consumption for vector 
       memoryPatternIDlookup += sizeof(std::vector<int>)*maxSector*getNPlanes();
-      // determine nunber of bits neede to fit the maximum index
+
+      // determine nunber of bits needed
+      uint32_t offsetTernary=1;
+      for(int nTernary=m_TSPmap->getNBits(layer);nTernary;nTernary--) {
+         offsetTernary *=3;
+      }
+      layerData.m_SSIDternaryByPattern.m_offsetTernary=offsetTernary;
+      uint32_t encodedSize=maxNDC*offsetTernary+1;
       int nbit;
-      for(nbit=0;iMax>(1U<<nbit);nbit++);
+      for(nbit=0;encodedSize>(1U<<nbit);nbit++);
       //
       // add space for ternary bits
-      nbit+= 2*m_TSPmap->getNBits(layer);
-      Info(where)<<"layer="<<layer<<" #dcSSID="<<iMax
+      Info(where)<<"layer="<<layer<<" #dcSSID="<<maxNDC
                  <<" DC bits="<< m_TSPmap->getNBits(layer)
+                 <<" encodedSize="<<encodedSize
                  <<" nbit="<<nbit<<"\n";
       // pattern bank data is stored in 8-bit or 16-bit words per layer
       if(nbit<=8) {
-         m_bank.m_pattern8Data[layer].resize(m_npatterns);
+         layerData.m_SSIDternaryByPattern.m_pattern8DataPacked.resize
+            (m_npatterns);
          memoryPatternIDlookup += sizeof(uint8_t)*m_npatterns;
       } else {
-         m_bank.m_pattern16Data[layer].resize(m_npatterns);
+         layerData.m_SSIDternaryByPattern.m_pattern16DataPacked.resize
+            (m_npatterns);
          memoryPatternIDlookup +=  sizeof(uint16_t)*m_npatterns;
       }
    }
 
    //
    // fill bank indexed by patternID
+#ifdef SEARCH_MEMORY_LEAK
+   printVmemUsage("readBankPostprocessing fill address-indexed bank");
+#endif
 
    // layer loop
    for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
-      LayerData const &layerData=m_bank.m_PatternByLayer[layer];
+      LayerData &layerData=m_bank.m_PatternByLayer[layer];
       //
       // encoding table dcIndexTable[sector][SSID] for the given layer
-      MAP<int,MAP<int,int> >
-         const &dcIndexTable(dcSSIDBySectorLayer[layer]);
+      VECTOR<MAP<int,int> >
+         const &encodedDCSSIDBySector(encodedDCSSIDbySectorLayer[layer]);
       //
       // number of DC bits in X,Y
       int nBitsX=m_TSPmap->getNBits(layer,0);
@@ -1941,184 +1814,158 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
          nBitsY=m_TSPmap->getNBits(layer,1);
       }
       // total number of ternary bits in this layer
-      int hbBitsLayer=nBitsX+nBitsY;
-      // total number of DC+HB bits in this layer
-      int dcHbBitsLayer=2*hbBitsLayer;
-      //
-      // lookup-tables to encode DC bits
-      std::vector<uint64_t> const &dcBitsLookup1(m_dcBitsLookup1[layer]);
-      std::vector<uint64_t> const &dcBitsLookup2(m_dcBitsLookup2[layer]);
+      int ternaryBitsLayer=nBitsX+nBitsY;
+      // total number of "normal" (HB) bit combinations
+      int nHB=1<<ternaryBitsLayer;
+      // lookup-table to merge HB bit of a given state
+      //   with existing ternary bits
+      int ternaryMax=layerData.m_SSIDternaryByPattern.m_offsetTernary;
+      VECTOR<VECTOR<uint16_t> > ternaryLookupTERNHB(nHB);
+      for(int iHB=0;iHB<nHB;iHB++) {
+         VECTOR<uint16_t> &ternaryLookup(ternaryLookupTERNHB[iHB]);
+         // lookup-table to merge HB bit of a given state
+         //   with existing ternary bits
+         ternaryLookup.reserve(ternaryMax+1);
+         // at index [0] store the HB "as is", but encoded in ternary logic
+         // this is used in case no previous pattern was filled
+         int iHBtern=0;
+         for(int bit=ternaryBitsLayer-1;bit>=0;bit--) {
+            iHBtern*=3;
+            if(iHB & (1<<bit)) {
+               iHBtern +=1;
+            }
+         }
+         ternaryLookup.push_back(iHBtern);
+         for(int iTERN=0;iTERN<ternaryMax;iTERN++) {
+            // iTERN: initial ternary bit setting
+            // iHB: initial HB setting
+            int ternaryResult=0;
+            int offset=ternaryMax/3;
+            for(int bit=ternaryBitsLayer-1;bit>=0;bit--) {
+               ternaryResult*=3;
+               int ternaryBit=(iTERN/offset)%3;
+               offset/=3;
+               if(ternaryBit != ((iHB>>bit)&1)) ternaryBit=2;
+               ternaryResult +=ternaryBit;
+            }
+            ternaryLookup.push_back(ternaryResult);
+         }
+      }
       //
       // loop over all SSIDs in this layer (in TSP space)
-      for(PatternBySectorSSidMap_t::const_ptr ssid=
+      for(PatternBySectorSSidMap_t::const_ptr iSSID=
              layerData.m_SSidData.beginPtr();
-          ssid!=layerData.m_SSidData.endPtr();++ssid) {
+          iSSID!=layerData.m_SSidData.endPtr();++iSSID) {
+
+         // get DC-level SSID
+         //    dcSSIDxy.first  : SSID in DC-space
+         //    dcSSIDxy.second : xy coordinate of TSP relative to DC
+         //
+         std::pair<int,int> dcSSIDxyNOGC= getDCssid(layer,(*iSSID).first);
+         // apply grey code for X,Y coordinates
+         // mask out xy overlap bit
+         uint32_t overlapXY=1<<nBitsX;
+         // grey coded HB part of SSID
+         uint32_t HBwithGC =
+            dcSSIDxyNOGC.second ^ ((dcSSIDxyNOGC.second & ~overlapXY)>>1);
+
+         // loopup-table to merge this dcSSID with an existing entry
+         VECTOR<uint16_t> lookupTERN(ternaryLookupTERNHB[HBwithGC]);
          //
-         // class to loop over all sectors
-         class DCBitExtractor {
+         // class to loop over all sectors and patterns
+         class DCBitExtractor
+            : public FTK_CompressedPatternListLoopWithCounter_base {
          public:
             inline DCBitExtractor
-            (int layer,std::pair<int,int> const &dcSSIDxy,int sector,
-             MAP<int,MAP<int,int> > const &dcIndexTable,int dcHbBitsLayer,
-             std::vector<uint64_t> const &dcBitsLookup1,
-             std::vector<uint64_t> const &dcBitsLookup2,
-             PatternBank &bank) : m_layer(layer),m_bank(bank) {
-               //
-               // get encoded SSID information
+            (int dcSSID,
+             VECTOR<MAP<int,int> > const &encodedDCSSIDbySector,
+             VECTOR<uint16_t> const &lookupTERNARY,LayerData &layerData,uint32_t hb)
+               : m_dcSSID(dcSSID),
+                 m_encodedDCSSIDbySector(encodedDCSSIDbySector),
+                 m_lookupTERNARY(lookupTERNARY),m_layerData(layerData) { m_hb=hb; }
+            inline bool setSector(uint32_t sector) {
+               // determine DC part of the encoded pattern data,
+               //    with zeroed ternary bits
                m_ssidIndex=-1;
-               MAP<int,MAP<int,int> >::const_iterator dcIndexThisSector=
-                  dcIndexTable.find(sector);
-               if(dcIndexThisSector!=dcIndexTable.end()) {
-                  MAP<int,int>::const_iterator ssidIndexPtr=
-                     (*dcIndexThisSector).second.find(dcSSIDxy.first);
-                  if(ssidIndexPtr!=(*dcIndexThisSector).second.end()) {
-                     //
-                     // m_ssidIndex is a (small) number which identifies
-                     //  the (TSP-)SSID, given (layer,sector)
-                     //
-                     // it is stored together with the ternary bit information
-                     // m_ssidIndex is shifted by dcHbBitsLayer
-                     //  to leave space for the ternary bit inflrmation
-                     m_ssidIndex=(*ssidIndexPtr).second << dcHbBitsLayer;
+               MAP<int,int> const &encodedDCSSID
+                  (m_encodedDCSSIDbySector[sector]);
+               MAP<int,int>::const_iterator iSSID=encodedDCSSID.find(m_dcSSID);
+               if(iSSID!=encodedDCSSID.end()) {
+                  m_ssidIndex=(*iSSID).second*
+                     m_layerData.m_SSIDternaryByPattern.m_offsetTernary
+                     +1;
+                  m_dataMax=m_layerData.m_SSIDternaryByPattern.
+                     m_dcSSIDbySectorIndex[sector].size()*
+                     m_layerData.m_SSIDternaryByPattern.m_offsetTernary  +1;
+                  if(m_ssidIndex>=m_dataMax) {
+                     std::cout<<"DCbitExractor SSID,sector "<<m_dcSSID<<" "<<sector
+                              <<" overflow "<<m_layerData.m_SSIDternaryByPattern.
+                        m_dcSSIDbySectorIndex[sector].size()
+                              <<" "<<m_ssidIndex<<">="<<m_dataMax
+                              <<"\n";
+                     exit(73);
                   }
+                  return true;
                }
-               m_dcHbInitial=dcBitsLookup1[dcSSIDxy.second];
-               m_dcHbMask=(1<<dcHbBitsLayer)-1;
-               m_dcBitsLookup=dcBitsLookup2.data()
-                  +m_dcHbInitial*(1<<dcHbBitsLayer);
-               
-            }
-            inline int getSSIDindex(void) const { return m_ssidIndex; }
-            inline void initialize(int firstPattern) {
-               m_pattern=firstPattern;
+               std::cout<<"DCbitExractor SSID,sector "<<m_dcSSID<<" "<<sector<<" not found\n";
+               exit(73);
+               return false;
             }
             inline void process(void) {
-               //
-               // transform xy coordinate of TSP relative to DC
-               //   to DC+HB bits
-               // Here, the ternary information is encoded as follows:
-               //
-               //   MSB ................LSB
-               //  ------+-----+------+-----
-               //   ~DCY | HBY | ~DCX | HBX
-               //
-               // ~DCY : logical-not of don't-care bits, Y-coordinate
-               //  HBY : y-coordinate of TSP relative to DC
-               // ~DCX : logical-not of don't-care bits, Y-coordinate
-               //  HBX : y-coordinate of TSP relative to DC
-               //
-               // there is a special case:
-               //  if both ~DC and HB are zero, the pattern is "invalid"
-               //  (it has not been filled yet
-               //
-               // In the original "cached" Bank (Class FTKTSPBank),
-               // if DC=1 (corresponds to ~DC=0) then
-               //   HB could be zero or one
-               // The setting of HB is not relevant if DC is set,
-               // but it is stored anyway
-               //
-               // in the encoding used here, if ~DC=0 then HB=1 to indicate
-               // a valid pattern
-               //
-               // here: calculate pattern address
-               //  dcOld : ternary bits of presently stored pattern
-               //  ssidWithDC : SSID index
-               uint32_t dcOld;
-               uint32_t ssidWithDC=m_ssidIndex;
-               if(m_bank.m_pattern8Data[m_layer].size()) {
-                 dcOld=m_bank.m_pattern8Data[m_layer][m_pattern];
-               } else {
-                 dcOld=m_bank.m_pattern16Data[m_layer][m_pattern];
-               }
-               // mask out non-DC bits
-               dcOld &= m_dcHbMask;
-               if(!dcOld) {
-                  //
-                  // first-time this patttern is set
-                  //    use initial DC information 
-                  ssidWithDC |= m_dcHbInitial;
-               } else {
-                  //
-                  // store OR of DC information from the new TSP-SSID
-                  // and the old DC bits
-                  ssidWithDC |= m_dcBitsLookup[dcOld];
-               }
-               // 
-               // store updated pattern information
-               if(m_bank.m_pattern8Data[m_layer].size()) {
-                  m_bank.m_pattern8Data[m_layer][m_pattern]=ssidWithDC;
+               // merge current bits with previously stored ternary bits
+               if(m_layerData.m_SSIDternaryByPattern.m_pattern8DataPacked.size()) {
+                  uint8_t &data= m_layerData.m_SSIDternaryByPattern.
+                     m_pattern8DataPacked[getPattern()];
+                  if(data) {
+                     data = (data-1)%m_layerData.m_SSIDternaryByPattern.
+                        m_offsetTernary+1;
+                  }
+                  data = m_lookupTERNARY[data] + m_ssidIndex;
                } else {
-                  m_bank.m_pattern16Data[m_layer][m_pattern]=ssidWithDC;
+                  uint16_t &data= m_layerData.m_SSIDternaryByPattern.
+                     m_pattern16DataPacked[getPattern()];
+                  if(data) {
+                     data = (data-1)%m_layerData.m_SSIDternaryByPattern.
+                        m_offsetTernary+1;
+                  }
+                  data = m_lookupTERNARY[data] + m_ssidIndex;
                }
             }
-            inline void update(int delta) {
-               m_pattern+=delta;
-            }
          protected:
-            uint32_t m_ssidIndex;
-            uint32_t m_dcHbInitial;
-            uint32_t m_dcHbMask;
-            int m_layer;
-            const uint64_t *m_dcBitsLookup;
-            int m_pattern;
-            PatternBank &m_bank;
+            uint32_t m_hb;
+            uint32_t m_dataMax;
+            uint16_t m_ssidIndex;
+            int m_dcSSID;
+            VECTOR<MAP<int,int> > const &m_encodedDCSSIDbySector;
+            VECTOR<uint16_t> const &m_lookupTERNARY;
+            LayerData &m_layerData;
          };
          //
-         // loop over all sectors with multiple patterns
-         for(PatternBySector_t::const_ptr sector=(*ssid).second.beginPtr();
-             sector!=(*ssid).second.endPtr();++sector) {
-            //
-            // get DC-level SSID
-            //    dcSSIDxy.first  : SSID in DC-space
-            //    dcSSIDxy.second : xy coordinate of TSP relative to DC
-            //
-            std::pair<int,int> dcSSIDxy=
-               getDCssid(layer,(*sector).first,(*ssid).first);
-
-            DCBitExtractor extractor
-               (layer,dcSSIDxy,(*sector).first,
-                dcIndexTable,dcHbBitsLayer,dcBitsLookup1,dcBitsLookup2,m_bank);
-            if(extractor.getSSIDindex()<0) {
-               Fatal(where)
-                  <<"problem with sector/SSID indexing (multi-pattern)\n";
-            }
-            //
-            // pattern data for this (layer,ssid,sector)
-            SectorData const &sectordata=(*sector).second;
-            patternLoop(extractor,
-                        layerData.m_CompressedDeltaBySector
-                        [(*sector).first].data()+sectordata.m_offset,
-                        sectordata.m_FirstPattern,sectordata.m_NPattern);
-         }
+         // loop over all patterns
+         DCBitExtractor extractor
+            (dcSSIDxyNOGC.first,encodedDCSSIDBySector,lookupTERN,layerData,HBwithGC);
+         (*iSSID).second.patternLoop(extractor);
       }
    }
    // count number of encoded patterns
    uint64_t nTSPpatterns=0;
-   std::vector<std::vector<int> > dcMask(dcSSIDBySectorLayer.size());
-   for(unsigned layer=0;layer<dcSSIDBySectorLayer.size();layer++) {
-      int nBitsX=m_TSPmap->getNBits(layer,0);
-      int nBitsY=0;
-      if(m_TSPmap->getDim(layer)==2) {
-         nBitsY=m_TSPmap->getNBits(layer,1);
-      }
-      for(int i=0;i<nBitsX;i++) {
-         dcMask[layer].push_back(1<<(i+nBitsX));
-      }
-      for(int i=0;i<nBitsY;i++) {
-         dcMask[layer].push_back(1<<(i+nBitsY+2*nBitsX));
-      }
-   }
    for(int iPattern=0;iPattern<m_npatterns;iPattern++) {
       int nTSP=1;
-      for(unsigned layer=0;layer<dcMask.size();layer++) {
-         int ssidWithDC;
-         if(m_bank.m_pattern8Data[layer].size()) {
-            ssidWithDC=m_bank.m_pattern8Data[layer][iPattern];
+      for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
+         int encodedSSIDwithDC=m_bank.m_PatternByLayer[layer].
+            m_SSIDternaryByPattern.getPackedData(iPattern);
+         if(encodedSSIDwithDC==0) {
+            if(!isReservedPatternId(iPattern)) {
+               Fatal(where)<<"invalid pattern "<<iPattern<<"\n";
+            }
+            nTSP=0;
          } else {
-            ssidWithDC=m_bank.m_pattern16Data[layer][iPattern];
-         }
-         for(unsigned i=0;i<dcMask[layer].size();i++) {
-            if(!(ssidWithDC & dcMask[layer][i])) nTSP<<=1;
+            // extract DC bits
+            std::pair<uint16_t,uint16_t> dchb=m_bank.m_PatternByLayer[layer].
+               m_SSIDternaryByPattern.getDCHB(iPattern);
+            // each DC bit doubles the number of TSP patterns
+            //  (m_nHit16 counts the number of bits)
+            nTSP <<= m_nHit16[dchb.first];
          }
       }
       nTSPpatterns += nTSP;
@@ -2128,6 +1975,10 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    for(unsigned i=0;i<patternTSPcount.size();i++)
       patternTSPcountTotal+= patternTSPcount[i];
 
+#ifdef SEARCH_MEMORY_LEAK
+   printVmemUsage("readBankPostprocessing printout");
+#endif
+
    Info(where)
       <<"number of distinct (layer,SSID)="<<ssidCountTotal
       <<" number of distinct (layer,SSID,sector)="<<sectorCountTotal
@@ -2142,7 +1993,7 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    Info(where)
       <<"average number of DC-patterns per sector="
       <<((sectorCountTotal > 0) ? m_npatterns/(double)sectorCountTotal : -1)
-      <<" min="<<minPattern<<" max="<<maxPattern<<"\n";
+      <<" min="<<patternsPerSector.First()<<" max="<<patternsPerSector.Last()<<"\n";
    for(unsigned i=0;i<patternTSPcount.size();i++) {
       Info(where)
          <<"plane="<<i<<" number of TSP/pattern="
@@ -2150,9 +2001,14 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
              : - 1) <<"\n";
 
    }
-   int memoryBuffers=2*sizeof(VECTOR<HitPattern_t>)+
-      (m_sectorUsage.size()+m_hitPatterns.size())*sizeof(HitPattern_t)+
-      sizeof(VECTOR<uint32_t>)+m_roadCand.size()*sizeof(uint32_t);
+   int memoryBuffers=2*sizeof(VECTOR<FTK_HitMask>)+
+      (m_SectorWC.size()+m_sectorUsage.size())*sizeof(FTK_HitMask)+
+      m_hitMask.memoryEstimate()
+#ifdef ROAD_CAND_AS_VECTOR
+      +sizeof(VECTOR<uint32_t>)
+      +m_roadCand.capacity()*sizeof(uint32_t)
+#endif
+      ;
    Info(where)
       <<"memory: SSID="<<memorySSIDlookup/1024/1024
       <<" MB, patternID="<<memoryPatternIDlookup/1024/1024
@@ -2176,16 +2032,14 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    // loop over all planes and SSIDS
    // check whether the SSID correponds to a valid module number
    int nPrint=100;
-   for(unsigned iPlane=0;iPlane<dcSSIDBySectorLayer.size();iPlane++) {
+   for(unsigned iPlane=0;iPlane<m_bank.m_PatternByLayer.size();iPlane++) {
       PatternBySectorSSidMap_t const &planeData=
          m_bank.m_PatternByLayer[iPlane].m_SSidData;
       for(PatternBySectorSSidMap_t::const_iterator
              iSSid=planeData.begin();iSSid!=planeData.end();++iSSid) {
          if(((*iSSid).first!=s_WILDCARDid)&&((*iSSid).first!=s_INVALIDid)) {
             int moduleId=-1;
-            getDCssidSlow(iPlane,
-                          (*(*iSSid).second.begin()).first,
-                          (*iSSid).first,&moduleId);
+            getDCssidSlow(iPlane,(*iSSid).first,&moduleId);
             int hash=-1;
             if(moduleId>=0) {
                if (getHWModeSS_tsp()==0) {
@@ -2208,6 +2062,8 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    }
    if(error) {
       Fatal(where)<<"invalid SSIDs ("<<error<<")in pattern bank\n";
+   } else {
+      Info(where)<<"no invalid SSIDs found in pattern bank\n";
    }
 
    // corruption test of sector structures
@@ -2215,22 +2071,25 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    // construct table of module IDs for each sector
    // verify that there is only one well-defined module per sector and plane
    error=0;
-   for(unsigned iPlane=0;iPlane<dcSSIDBySectorLayer.size();iPlane++) {
+   for(unsigned iPlane=0;iPlane<m_bank.m_PatternByLayer.size();iPlane++) {
       VECTOR<std::set<int> > modulesBySector(maxSector);
+
       PatternBySectorSSidMap_t const &planeData=
          m_bank.m_PatternByLayer[iPlane].m_SSidData;
+
       for(PatternBySectorSSidMap_t::const_iterator
              iSSid=planeData.begin();iSSid!=planeData.end();++iSSid) {
-         for(PatternBySector_t::const_iterator
-                iSector=(*iSSid).second.begin();
-             iSector!=(*iSSid).second.end();++iSector) {
-            int moduleId=-1;
-            if(((*iSSid).first!=s_WILDCARDid)&&(*iSSid).first!=s_INVALIDid) {
-               getDCssidSlow(iPlane,(*iSector).first,(*iSSid).first,&moduleId);
-            }
-            modulesBySector[(*iSector).first].insert(moduleId);
+         int module=-1;
+         int ssid=(*iSSid).first;
+         if((ssid!=s_WILDCARDid)&&ssid!=s_INVALIDid) {
+            getDCssidSlow(iPlane,ssid,&module);
          }
-      }
+         for(FTK_CompressedSectorPatternList::const_iterator
+                iSector=(*iSSid).second.begin();iSector!=(*iSSid).second.end();
+             iSector++) {
+            modulesBySector[(*iSector).first].insert(module);
+         }
+      } 
       std::map<int,int> multiplicity;
       for(size_t sector=0;sector<modulesBySector.size();sector++) {
          multiplicity[modulesBySector[sector].size()]++;
@@ -2258,9 +2117,14 @@ void FTK_CompressedAMBank::readBankPostprocessing(char const *where) {
    if(error) {
       Fatal(where)
          <<"Multiple modules are assigned to a given plane and sector\n";
+   } else {
+      Info(where)<<"Pattern bank modules per sector are consistent\n";
    }
 #endif
    setupSectorWildcards();
+#ifdef SEARCH_MEMORY_LEAK
+   printVmemUsage("readBankPostprocessing end");
+#endif
 }
 
 /**
@@ -2455,12 +2319,10 @@ void FTK_CompressedAMBank::exportBadModuleTTree
  */
 
 void FTK_CompressedAMBank::setupSectorWildcards(void) {
-   int maxSector=0;
-   if(m_SectorFirstLastPattern.rbegin()!=m_SectorFirstLastPattern.rend()) 
-      maxSector=(*m_SectorFirstLastPattern.rbegin()).first+1;
+   uint32_t maxSector=m_bank.m_PatternRangeBySector.size();
    m_SectorWC.resize(0);
    m_SectorWC.resize(maxSector);
-   VECTOR<HitPattern_t> sectorBadList(maxSector);
+   VECTOR<FTK_HitMask> sectorBadList(maxSector);
    
    // store wildcards in sector table and in list of bad SSIDs
    for(int iPlane=0;iPlane<getNPlanes();iPlane++) {
@@ -2491,9 +2353,7 @@ void FTK_CompressedAMBank::setupSectorWildcards(void) {
             // ignore inside bank
             mask=4;
          } else {
-            PatternBySector_t::const_iterator iSector=
-               (*iSSid).second.begin();
-            getDCssidSlow(iPlane,(*iSector).first,(*iSSid).first,&moduleId);
+            getDCssidSlow(iPlane,(*iSSid).first,&moduleId);
             MAP<int,int>::const_iterator im=
                m_badModules[iPlane].find(moduleId);
             if(im!=m_badModules[iPlane].end()) {
@@ -2504,19 +2364,13 @@ void FTK_CompressedAMBank::setupSectorWildcards(void) {
                }
             }
          }
-         for(PatternBySector_t::const_iterator
+         for(FTK_CompressedSectorPatternList::const_iterator
                 iSector=(*iSSid).second.begin();
              iSector!=(*iSSid).second.end();++iSector) {
             sectorFlag[(*iSector).first]|=mask;
-            /*if((*iSector).first==1273) {
-               std::cout<<" SSID="<<(*iSSid).first
-                        <<" plane="<<iPlane
-                        <<" module="<<moduleId
-                        <<" mask="<<mask<<"\n";
-                        } */
          }
       }
-      for(int sector=0;sector<maxSector;sector++) {
+      for(uint32_t sector=0;sector<maxSector;sector++) {
          int type=sectorFlag[sector];
          if(type==0) continue; // no data for this sector
          if(type==1) continue;  // no dead module
@@ -2531,7 +2385,7 @@ void FTK_CompressedAMBank::setupSectorWildcards(void) {
                    iSSid=planeData.begin();iSSid!=planeData.end();++iSSid) {
                int moduleId=-1;
                bool doPrint=false;
-               for(PatternBySector_t::const_iterator
+               for(FTK_CompressedSectorPatternList::const_iterator
                       iSector=(*iSSid).second.begin();
                    iSector!=(*iSSid).second.end();++iSector) {
                   if((*iSector).first==sector) doPrint=true;
@@ -2547,7 +2401,7 @@ void FTK_CompressedAMBank::setupSectorWildcards(void) {
                   }
                   if(((*iSSid).first!=s_WILDCARDid)&&
                      ((*iSSid).first!=s_INVALIDid)) {
-                     getDCssidSlow(iPlane,(*(*iSSid).second.begin()).first,(*iSSid).first,&moduleId);
+                     getDCssidSlow(iPlane,(*iSSid).first,&moduleId);
                   }
                   int hash=-2;
                   if(moduleId>=0) {
@@ -2560,7 +2414,7 @@ void FTK_CompressedAMBank::setupSectorWildcards(void) {
                            <<" module="<<moduleId
                            <<" hash="<<hash
                            <<" [";
-                  for(PatternBySector_t::const_iterator
+                  for(FTK_CompressedSectorPatternList::const_iterator
                          iSector=(*iSSid).second.begin();
                       iSector!=(*iSSid).second.end();++iSector) {
                      std::cout<<" "<<(*iSector).first;
@@ -2675,83 +2529,81 @@ int FTK_CompressedAMBank::compare(FTK_CompressedAMBank const *bank) const {
             error |= 0x0010;
             continue;
          }
-         
-         MAP<int,VECTOR<uint32_t> > patternData1,patternData2;
-
-         class PatternExtractor {
-         public:
-            inline PatternExtractor(VECTOR<uint32_t> &data) : m_data(data),m_pattern(0){ }
-            inline void initialize(uint32_t first) { m_pattern=first; }
-            inline void process(void) {
-               m_data.push_back(m_pattern);
+         size_t nmax=0;
+         for(FTK_CompressedSectorPatternList::const_iterator
+                sector1=(*ssid1).second.begin(),
+                sector2=(*ssid2).second.begin();
+             (sector1!=(*ssid1).second.end())&&
+                (sector2!=(*ssid2).second.end());++sector1,++sector2) {
+            if(((*sector1).first!=(*sector2).first)&&(!(error & 0x1000))) {
+               Info("compare")
+                  <<"sector number mismatch (layer="<<layer
+                  <<" ssid="<<(*ssid1).first<<") "
+                  <<(*sector1).first<<"!="<<(*sector2).first<<"\n";
+               error |= 0x0100;
             }
-            inline void update(uint32_t delta) {
-               m_pattern+=delta;
+            // extract pattern data and compare
+            if((*sector1).second.getNPattern()>nmax) {
+               nmax=(*sector1).second.getNPattern();
+            }
+            if((*sector2).second.getNPattern()>nmax) {
+               nmax=(*sector2).second.getNPattern();
             }
-         protected:
-            VECTOR<uint32_t> &m_data;
-            uint32_t m_pattern;
-         };
-         for(PatternBySector_t::const_ptr sector1=(*ssid1).second.beginPtr();
-              sector1!=(*ssid1).second.endPtr();++sector1) {
-            PatternExtractor extractor(patternData1[(*sector1).first]);
-            patternLoop(extractor,
-                        thisLayerData.m_CompressedDeltaBySector
-                        [(*sector1).first].data()+(*sector1).second.m_offset,
-                        (*sector1).second.m_FirstPattern,
-                        (*sector1).second.m_NPattern);
-         }
-         for(PatternBySector_t::const_ptr sector2=(*ssid2).second.beginPtr();
-              sector2!=(*ssid2).second.endPtr();++sector2) {
-            PatternExtractor extractor(patternData2[(*sector2).first]);
-            patternLoop(extractor,
-                        otherLayerData.m_CompressedDeltaBySector
-                        [(*sector2).first].data()+(*sector2).second.m_offset,
-                        (*sector2).second.m_FirstPattern,
-                        (*sector2).second.m_NPattern);
          }
-         MAP<int,VECTOR<uint32_t> >::const_iterator sector1,sector2;
-         for(sector1=patternData1.begin(),sector2=patternData2.begin();
-             (sector1!=patternData1.end())&&(sector2!=patternData2.end());
-             sector1++,sector2++) {
-            if((*sector1).first != (*sector2).first) {
-               if((error & 0x0100)==0) {
+         if(!error) {
+            VECTOR<uint8_t> data1,data2;
+            data1.reserve(nmax*4);
+            data2.reserve(nmax*4);
+            for(FTK_CompressedSectorPatternList::const_iterator
+                sector1=(*ssid1).second.begin(),
+                sector2=(*ssid2).second.begin();
+             (sector1!=(*ssid1).second.end())&&
+                (sector2!=(*ssid2).second.end());++sector1,++sector2) {
+               if(((*sector1).second.getNPattern()!=
+                   (*sector2).second.getNPattern())&&(!(error & 0x2000))) {
                   Info("compare")
-                     <<"sector number mismatch (layer="<<layer
-                     <<" ssid="<<(*ssid1).first<<") "
-                     <<(*sector1).first<<"!="<<(*sector2).first<<"\n";
+                     <<"number of patterns mismatch (layer="<<layer
+                     <<" ssid="<<(*ssid1).first<<" sector="
+                     <<(*sector1).first<<") "<<(*sector1).second.getNPattern()
+                     <<"!="<<(*sector2).second.getNPattern()<<"\n";
+                  error |= 0x2000;
                }
-               error |= 0x0100;
-               continue;
-            }
-            VECTOR<uint32_t> const &sectordata1=(*sector1).second;
-            VECTOR<uint32_t> const &sectordata2=(*sector2).second;
-            int errOld=error;
-            if(sectordata1.size()!=sectordata2.size()) error |= 0x2000;
-            for(unsigned i=0;i<sectordata1.size();i++) {
-               if(sectordata1[i]!=sectordata2[i]) {
-                  error |= 0x8000;
+               uint32_t first1,first2;
+               (*sector1).second.encode(FTK_CompressedPatternList::ENCODING_U32,
+                                        &first1,data1);
+               (*sector2).second.encode(FTK_CompressedPatternList::ENCODING_U32,
+                                        &first2,data2);
+               if(first1!=first2) {
+                  Info("compare")
+                     <<"first pattern mismatch (layer="<<layer
+                     <<" ssid="<<(*ssid1).first<<" sector="
+                     <<(*sector1).first<<") "<<first1<<"!="<<first2<<"\n";
+                  error|=0x4000;
                   break;
                }
-            }
-            if(errOld != error) {
-               Info("compare")
-                  <<"bank data mismatch (layer="<<layer
-                  <<" ssid="<<(*ssid1).first<<" sector="<<(*sector1).first
-                  <<") error=0x"<<std::setbase(16)<<(error^errOld)
-                  <<std::setbase(10)<<"\n";
+               if(data1.size()!=data2.size()) {
+                  Info("compare")
+                     <<"pattern data size mismatch (layer="<<layer
+                     <<" ssid="<<(*ssid1).first<<" sector="
+                     <<(*sector1).first<<") "<<data1.size()<<"!="
+                     <<data2.size()<<"\n";
+                  error|=0x8000;
+               }
+               if(memcmp(data1.data(),data2.data(),data1.size())) {
+                  std::ostream &log=Info("compare");
+                  log<<"pattern data mismatch (layer="<<layer
+                     <<" ssid="<<(*ssid1).first<<" sector="
+                     <<(*sector1).first;
+                  for(size_t l=0;l<data1.size();l++) {
+                     if(data1[l]!=data2[l]) {
+                        log<<" ["<<l<<"] "<<(int)data1[l]<<"!="<<(int)data2[l];
+                     }
+                  }
+                  log<<")\n";
+                  error|=0x10000;
+               }
             }
          }
-         if(((error & 0x0200)==0) && ((sector1!=patternData1.end())||
-                                      (sector2!=patternData2.end()))) {
-            Info("compare")
-               <<"different number of sectors (layer="<<layer
-               <<" ssid="<<(*ssid1).first
-               <<" )"<<thisLayerData.m_SSidData.size()
-               <<"!="<<otherLayerData.m_SSidData.size()
-               <<"\n";
-            error |= 0x0200;
-         }
       }
       if(((error & 0x0020)==0)&&((ssid1!=thisLayerData.m_SSidData.endPtr())||
                                  (ssid2!=otherLayerData.m_SSidData.endPtr())))
@@ -2814,6 +2666,9 @@ int FTK_CompressedAMBank::readCCachedBank(TDirectory *inputDir) {
       if(layer<0) {
          continue;
       }
+#ifdef SEARCH_MEMORY_LEAK
+      printVmemUsage("readCCachedBank "+name);
+#endif
       LayerData &layerData=m_bank.m_PatternByLayer[layer];
       if(name.BeginsWith("Layer")) {
          TTree *tree;
@@ -2822,51 +2677,34 @@ int FTK_CompressedAMBank::readCCachedBank(TDirectory *inputDir) {
             int nSector=tree->GetEntries();
             Int_t ssidVar,sectorVar,firstPatternVar,nPatternVar;
             Int_t nDataVar;
-            tree->SetBranchAddress("ssid",&ssidVar);
-            tree->SetBranchAddress("sector",&sectorVar);
-            tree->SetBranchAddress("firstPattern",&firstPatternVar);
-            tree->SetBranchAddress("nPattern",&nPatternVar);
-               tree->SetBranchAddress("nData",&nDataVar);
+            tree->SetBranchAddress("nData",&nDataVar);
             int dataSize=0;
-            tree->SetBranchStatus("sector");
-            tree->SetBranchStatus("nData");
-            MAP<int,int> sectorSize;
+            /* tree->SetBranchStatus("sector");
+               tree->SetBranchStatus("nData"); */
             for(int i=0;i<nSector;i++) {
                tree->GetEntry(i);
                if(nDataVar>dataSize) dataSize=nDataVar;
-               sectorSize[sectorVar]+=nDataVar;
-            }
-            int maxSector=(*sectorSize.rbegin()).first+1;
-            VECTOR<int> sectorOffset(maxSector);
-            layerData.m_CompressedDeltaBySector.resize(maxSector);
-            for(MAP<int,int>::const_iterator isector=sectorSize.begin();
-                isector!=sectorSize.end();isector++) {
-               layerData.m_CompressedDeltaBySector[(*isector).first].resize
-                  ((*isector).second);
             }
             std::vector<Int_t> data(dataSize);
+            tree->SetBranchAddress("sector",&sectorVar);
+            tree->SetBranchAddress("ssid",&ssidVar);
+            tree->SetBranchAddress("firstPattern",&firstPatternVar);
+            tree->SetBranchAddress("nPattern",&nPatternVar);
             tree->SetBranchAddress("data",data.data());
-            tree->SetBranchStatus("data");
+            /* tree->SetBranchStatus("data");
             tree->SetBranchStatus("ssid");
             tree->SetBranchStatus("firstPattern");
-            tree->SetBranchStatus("nPattern");
+            tree->SetBranchStatus("nPattern"); */
             Info("readCCachedBank")<<"nSector="<<nSector
                                    <<" buffer size="<<data.size()<<"\n";
             for(int i=0;i<nSector;i++) {
                tree->GetEntry(i);
-               SectorData &sectordata=layerData.m_SSidData[ssidVar][sectorVar];
-               sectordata.m_FirstPattern=firstPatternVar;
-               sectordata.m_NPattern=nPatternVar;
-               sectordata.m_offset=sectorOffset[sectorVar];
-               sectordata.m_length=nDataVar;
-               uint8_t * __restrict dest=
-                  layerData.m_CompressedDeltaBySector[sectorVar].data()+
-                  sectordata.m_offset;
-               for(int i=0;i<nDataVar;i++) {
-                  (*dest++)=data[i];
-               }
-               sectorOffset[sectorVar]+=nDataVar;
+               layerData.m_SSidData[ssidVar].importData
+                  (sectorVar,firstPatternVar,nPatternVar,
+                   FTK_CompressedPatternList::ENCODING_DELTA,
+                   nDataVar,data.data());
             }
+            delete tree;
          } else {
             Error("readCCachedBank")<<"TObject "<<name<<" is not a TTree\n";
             error++;
@@ -2900,7 +2738,7 @@ int FTK_CompressedAMBank::readCCachedBank(TDirectory *inputDir) {
     data[nData] : compressed pattern data
 */
 int FTK_CompressedAMBank::writeCCachedBankFile(char const *filename,int flatFormat) const {
-   int error;
+   int error=1;
    if(flatFormat==0) {
       TDirectory *out=FTKRootFile::Instance()->CreateRootFile(filename);
       if(out) {
@@ -2911,8 +2749,6 @@ int FTK_CompressedAMBank::writeCCachedBankFile(char const *filename,int flatForm
          Error("writeCCachedBankFile")
             <<" could not open \""<<filename<<"\" for writing\n";
       }
-   } else {
-      error=writeBANKjson(filename);
    }
    return error;
 }
@@ -2922,49 +2758,41 @@ int FTK_CompressedAMBank::writeCCachedBankFile(TDirectory *out) const {
    TDirectory *back=gDirectory;
    out->cd();
    for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
+      //std::cout<<"Write layer "<<layer<<"\n";
       LayerData const &layerData=m_bank.m_PatternByLayer[layer];
       TString treeName(TString::Format("Layer%d",layer));
       TTree *ssidTree=new TTree(treeName,treeName);
-      int maxDataSize=0;
-      for(PatternBySectorSSidMap_t::const_ptr ssid=
-             layerData.m_SSidData.beginPtr();
-          ssid!=layerData.m_SSidData.endPtr();++ssid) {
-         for(PatternBySector_t::const_ptr sector=(*ssid).second.beginPtr();
-             sector!=(*ssid).second.endPtr();++sector) {
-            int nword=(*sector).second.m_length;
-            if(nword>maxDataSize) maxDataSize=nword;
-         }
-      }
-      /* Info("writeCCachedBankFile")
-         <<"layer="<<layer
-         <<" maxDeltaSize="<<maxDataSize<<"\n"; */
       Int_t ssidVar,sectorVar,firstPatternVar,nPatternVar,nDataVar;
-      std::vector<Int_t> data(maxDataSize);
+      std::vector<Int_t> data(1);
       ssidTree->Branch("ssid",&ssidVar,"ssid/I");
       ssidTree->Branch("sector",&sectorVar,"sector/I");
       ssidTree->Branch("firstPattern",&firstPatternVar,"firstPattern/I");
       ssidTree->Branch("nPattern",&nPatternVar,"numPattern/I");
-      if(maxDataSize) {
-         ssidTree->Branch("nData",&nDataVar,"nData/I");
-         ssidTree->Branch("data",data.data(),"data[nData]/I");
-      }
+      ssidTree->Branch("nData",&nDataVar,"nData/I");
+      ssidTree->Branch("data",data.data(),"data[nData]/I");
+
       for(PatternBySectorSSidMap_t::const_ptr ssid=
              layerData.m_SSidData.beginPtr();
           ssid!=layerData.m_SSidData.endPtr();++ssid) {
          ssidVar=(*ssid).first;
-         for(PatternBySector_t::const_ptr sector=(*ssid).second.beginPtr();
-             sector!=(*ssid).second.endPtr();++sector) {
+         //int ntotal=0;
+         for(FTK_CompressedSectorPatternList::const_iterator
+                sector=(*ssid).second.begin();
+             sector!=(*ssid).second.end();++sector) {
             sectorVar=(*sector).first;
-            firstPatternVar=(*sector).second.m_FirstPattern;
-            nPatternVar=(*sector).second.m_NPattern;
-            nDataVar=(*sector).second.m_length;
-            uint8_t const *  __restrict compressedDeltaData=layerData.
-               m_CompressedDeltaBySector[sectorVar].data()+
-               (*sector).second.m_offset;
-            for(int i=0;i<nDataVar;i++)
-               data[i]=compressedDeltaData[i];
+            Int_t encoding;
+            (*sector).second.exportData
+               (&firstPatternVar,&nPatternVar,&encoding,data);
+            if(encoding!=FTK_CompressedPatternList::ENCODING_DELTA) {
+               Fatal("writeCCachedBankFile")
+                  <<"pattern encoding "<<encoding<<" not supported\n";
+            }
+            nDataVar=data.size();
+            //ntotal+=nDataVar;
+            if(nDataVar>0) ssidTree->SetBranchAddress("data",data.data());
             ssidTree->Fill();
          }
+         //std::cout<<"Write SSID "<<ssidVar<<" "<<ntotal<<"\n";
       }
       ssidTree->Write("", TObject::kOverwrite);      
       Info("writeCCachedBankFile")
@@ -2977,194 +2805,6 @@ int FTK_CompressedAMBank::writeCCachedBankFile(TDirectory *out) const {
    return error;
 }
 
-void  FTK_CompressedAMBank::SplitlistHUF
-(uint64_t code,int *i2char,int *integral,int i0,int i1,
- VECTOR<int> &huftable,VECTOR<uint64_t> &hufcode) const {
-   if(i0==i1) {
-      huftable.push_back(0);
-      huftable.push_back(i2char[i0]);
-      hufcode[i2char[i0]]=code;
-   } else {
-      int thresh=(integral[i0]+integral[i1])/2;
-      int j0=i0;
-      int j1=i1;
-      while(j0<j1) {
-         int j2=(j0+j1)/2;
-         if(integral[j2]<=thresh) {
-            j0=j2+1;
-         } else {
-            j1=j2;
-         }
-      }
-      int hufindex=huftable.size();
-      huftable.push_back(0);
-      SplitlistHUF((code<<1)+1,i2char,integral,j0,i1,huftable,hufcode);
-      huftable[hufindex]=huftable.size()-hufindex;
-      SplitlistHUF((code<<1),i2char,integral,i0,j0-1,huftable,hufcode);
-   }
-}
-
-int FTK_CompressedAMBank::writeBANKjson(char const *jsonFile) const {
-   int error=0;
-   std::ofstream out(jsonFile);
-   MAP< int,VECTOR< MAP<int,MAP<int,SectorData const *> > > > tspBySectorDC;
-
-#ifdef JSON_HUF
-   // set up tables for huf encoding
-   VECTOR<VECTOR<int> > multiplicity(m_bank.m_PatternByLayer.size());
-   VECTOR<VECTOR<int> > huftable(m_bank.m_PatternByLayer.size());
-   VECTOR<VECTOR<int> > hufcodeSize(m_bank.m_PatternByLayer.size());
-   VECTOR<VECTOR<uint64_t> > hufcode(m_bank.m_PatternByLayer.size());
-#endif
-   for(unsigned layer=0;layer<m_bank.m_PatternByLayer.size();layer++) {
-#ifdef JSON_HUF
-      multiplicity[layer].resize(256);
-#endif
-      LayerData const &layerData=m_bank.m_PatternByLayer[layer];
-      for(PatternBySectorSSidMap_t::const_ptr ssid=
-             layerData.m_SSidData.beginPtr();
-          ssid!=layerData.m_SSidData.endPtr();++ssid) {
-         for(PatternBySector_t::const_ptr sector=(*ssid).second.beginPtr();
-             sector!=(*ssid).second.endPtr();++sector) {
-            VECTOR< MAP<int,MAP<int,SectorData const *> > >
-               &layerData=tspBySectorDC[(*sector).first];
-            if(!layerData.size()) layerData.resize(getNPlanes());
-            int dc=getDCssidConst(layer,(*ssid).first);
-            SectorData const *sd=&(*sector).second;
-            layerData[layer][dc][(*ssid).first]=sd;
-#ifdef JSON_HUF
-            uint8_t const *ptr=m_bank.m_PatternByLayer[layer]
-               .m_CompressedDeltaBySector[(*sector).first].data()+sd->m_offset;
-            for(int i=sd->m_length;i;i--) {
-               multiplicity[layer][*(ptr++)]++;
-            }
-#endif
-         }
-      }
-#ifdef JSON_HUF
-      MAP<int64_t,int> ordered;
-      for(int i=0;i<256;i++) {
-         if(multiplicity[layer][i]) {
-            ordered[(multiplicity[layer][i]<<8)+i]=i;
-         }
-      }
-      Info("writeBANKjson")<<"layer "<<layer
-                           <<" HUF tree number of characters "
-                           <<ordered.size()<<"\n";
-      int sum=0,ii=0;
-      int integral[256],i2char[256];
-      for(MAP<int64_t,int>::const_iterator i=ordered.begin();
-          i!=ordered.end();i++) {
-         sum += (*i).first>>8;
-         integral[ii]=sum;
-         i2char[ii++]=(*i).second;
-      }
-      hufcode[layer].resize(256);
-      hufcodeSize[layer].resize(256);
-      SplitlistHUF(1,i2char,integral,0,ordered.size()-1,huftable[layer],
-                   hufcode[layer]);
-      for(int i=0;i<256;i++) {
-         int b;
-         for(b=31;b;b--) {
-            if(hufcode[layer][i] & (1<<b)) break;
-         }
-         hufcodeSize[layer][i]=b;
-      }
-#endif
-   }
-   
-
-   Info("writeBANKjson")<<"output file=\""<<jsonFile<<"\"\n";
-#ifdef JSON_HUF
-   out<<"{\"huftables\":[\n";
-   for(int l=0;l<huftable.size();l++) {
-      if(l)out<<",\n";
-      out<<"{\"layer\":"<<l<<",\"huf\":[\n";
-      for(int i=0;i<huftable[l].size();i++) {
-         if(i) out<<",";
-         out<<huftable[l][i];
-      }
-      out<<"\n]}\n";
-   }
-   out<<"],";
-#else
-   out<<"{";
-#endif
-   out<<"\"patterns\":[";
-   for( MAP< int,VECTOR< MAP<int, MAP<int,SectorData const *> > > >
-           ::const_iterator
-           iSector=tspBySectorDC.begin();iSector!=tspBySectorDC.end();
-        iSector++) {
-      if(iSector!=tspBySectorDC.begin()) out<<",\n";
-      int sector=(*iSector).first;
-      std::pair<int,int> firstLast=
-         (*m_SectorFirstLastPattern.find(sector)).second;
-      out<<"{\"sector\":"<<sector
-         <<",\"first\":"<<firstLast.first
-         <<",\"last\":"<<firstLast.second
-         <<",[\n";
-      for(unsigned layer=0;layer<(*iSector).second.size();layer++) {
-         MAP<int, MAP<int,SectorData const *> >
-            const &ssidData((*iSector).second[layer]);
-         if(layer) out<<",\n";
-         out<<" {\"layer\":"<<layer<<",[\n";
-         for(MAP<int, MAP<int,SectorData const *> >::const_iterator
-                iDC=ssidData.begin();iDC!=ssidData.end();
-             iDC++) {
-            if(iDC!=ssidData.begin()) out<<",\n";
-            out<<"  {\"DCssid\":"<<(*iDC).first<<",\"tspList\":[\n";
-            for(MAP<int,SectorData const *>::const_iterator
-                   iTSP=(*iDC).second.begin();
-                iTSP!=(*iDC).second.end();iTSP++) {
-               SectorData const *sd=(*iTSP).second;
-               if(iTSP!=(*iDC).second.begin()) out<<",\n";
-               out<<"   {\"TSPssid\":"<<(*iTSP).first
-                  <<",\"first\":"<<sd->m_FirstPattern
-                  <<",\"nPatt\":"<<sd->m_NPattern
-                  <<",\"nData\":"<<sd->m_length
-                  <<",\"data\":\"";
-               uint8_t const *ptr=m_bank.m_PatternByLayer[layer]
-                  .m_CompressedDeltaBySector[sector].data()+sd->m_offset;
-#ifdef JSON_HUF
-               char c=0;
-               int ibit=5;
-               for(int i=sd->m_length;i;i--) {
-                  int data=*(ptr++);
-                  uint64_t code=hufcode[layer][data];
-                  for(int b=hufcodeSize[layer][data];b>=0;b--) {
-                     if(code & (1LL<<b)) c|=(1<<ibit);
-                     ibit--;
-                     if(ibit<0) {
-                        out<<(char)(c+'0');
-                        c=0;
-                        ibit=5;
-                     }
-                  }
-               }
-               if(ibit!=5) out<<(char)(c+'0');
-#else
-               for(int i=sd->m_length;i;i--) {
-                  uint8_t data=*(ptr++)+0x33;
-                  if((data>=23)&&(data<127)&&(data!='\\')) {
-                     out<<(char)data;
-                  } else {
-                     out<<"\\h"<<std::setbase(16)<<std::setw(2)
-                        <<(int)data<<std::setbase(10);
-                  }
-               }
-#endif
-               out<<"\"}";
-            }
-            out<<"]}";
-         }
-         out<<"\n ]}";
-      }
-      out<<"\n]}";
-   }
-   out<<"\n]\n}\n";
-   return error;
-}
-
 void FTK_CompressedAMBank::insertPatterns
 (int sector,FTKPatternOneSector const *patterns,
  int maxpatts,VECTOR<HitPatternMap_t> &dcPatterns,
@@ -3188,11 +2828,10 @@ void FTK_CompressedAMBank::insertPatterns
       // this variables stores DC/HB bits of all layers
       uint64_t dchb0=0;
       //std::cout<<"Pattern\n";
-      HitPattern_t badModules=0;
-      HitPattern_t wildcardRequest=0;
+      FTK_HitMask badModules=0;
+      FTK_HitMask wildcardRequest=0;
       for(int ilayer=nLayer-1;ilayer>=0;ilayer--) {
-         std::pair<int,int> const &dcSSID=
-            getDCssid(ilayer,sector,tsp.GetHit(ilayer));
+         std::pair<int,int> const &dcSSID=getDCssid(ilayer,tsp.GetHit(ilayer));
          int nDCbits=m_TSPmap->getNBits(ilayer);
          int nDCHBbits=nDCbits<<1; 
          /* std::cout<<" L"<<ilayer<<" tsp="<<tsp.GetHit(ilayer)
@@ -3549,7 +3188,6 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
       for(std::list<FTK_CompressedAMBank::Partition>::const_iterator
              iPartition=partitionList.begin();iPartition!=partitionList.end();
           iPartition++) {
-         maxpatts+=(*iPartition).fNumPatternMax;
          // the FTKPatternBySectorBlockReader is reading the patterns
          // sector-by-sector, in a pre-defined coverage range
          //
@@ -3569,7 +3207,8 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
          Info("readSectorOrderedBank")
             <<"reading from "<<name<<" nLayer="<<TSPreader->GetNLayers()
             <<" partition "<<partitionCount<<" maxpattern="
-            <<(*iPartition).fNumPatternMax<<" maxSector="<<(*iPartition).fNumSectorMax
+            <<(*iPartition).fNumPatternMax
+            <<" maxSector="<<(*iPartition).fNumSectorMax
             <<"\n";
          // the coverage map holds for each coverage the number of patterns
          // it is used in order to estimate down to which coverage the patterns
@@ -3582,7 +3221,6 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
 #ifdef SEARCH_MEMORY_LEAK
          printVmemUsage("after GetNPatternsByCoverage");
 #endif
-         std::map<int,int>::const_reverse_iterator i=coverageMap.rbegin();
          TSPreader->Rewind();
 #ifdef SEARCH_MEMORY_LEAK
          printVmemUsage("after Rewind");
@@ -3592,6 +3230,7 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
          uint32_t totalPatterns=0;
          uint64_t totalPatternsCoverage=0;
          int nDC0=nDC;
+         maxpatts=nDC0+(*iPartition).fNumPatternMax;
          for(std::map<int,int>::const_iterator j=coverageMap.begin();
              j!=coverageMap.end();j++) {
             totalPatterns += (*j).second;
@@ -3603,27 +3242,26 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
             <<" average coverage: "
             <<(totalPatterns ? (totalPatternsCoverage/(double)totalPatterns):0)
             <<"\n";
-         int covEnd;
          std::set<int> loadedSectorList;
          int maxNumSector=(*iPartition).fNumSectorMax;
          if(maxNumSector<0) maxNumSector=(*iPartition).fSectorSet.size();
-         do {
-            std::map<int,int>::const_reverse_iterator j=i;
-            int npattEstimate=nDC;
-            covEnd=(*i).first;
-            while((j!=coverageMap.rend())&&(npattEstimate<maxpatts)) {
-               npattEstimate += (*j).second;
-               covEnd=(*j).first;
-               j++;
-            }
-            Info("readSectorOrderedBank")
-               <<"adding coverage range "<<(*i).first<<"-"<<covEnd
-               <<" extra patterns="<<npattEstimate-nDC<<"\n";
+         // loop over coverage ranges
+         // starting with coverage indicated by (*i)
+         bool tooFew=true;
+         int covEnd=0;
+         for(std::map<int,int>::const_reverse_iterator i=coverageMap.rbegin();
+             i!=coverageMap.rend();) {
+            // read a minimum of one coverages
+            int nAvail=0;
+            int covBegin=(*i).first;
+            do {
+               nAvail +=(*i).second;
+               covEnd=(*i).first;
+               i++;
+            } while((nDC+nAvail<=maxpatts)&&(i!=coverageMap.rend()));
             // read all patterns in the given coverage range
-            // (not reading the smallest coverage)
-            // these patterns for sure will fit into the DC bank
-            //for(int sector=TSPreader->GetFirstSector();sector>=0;
-            //    sector=TSPreader->GetNextSector(sector)) {
+            int nTSPold=nTSP;
+            int nDCold=nDC;
             for(std::set<int>::const_iterator sectorPtr=
                    (*iPartition).fSectorSet.begin();
                 sectorPtr!=(*iPartition).fSectorSet.end();sectorPtr++) {
@@ -3632,42 +3270,46 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
                   if((int)loadedSectorList.size()>=maxNumSector) continue;
                   loadedSectorList.insert(sector);
                }
-               FTKPatternOneSector *patterns=TSPreader->Read(sector,covEnd+1);
+               FTKPatternOneSector *patterns=
+                  TSPreader->Read(sector,covEnd);
                if(patterns) {
                   insertPatterns(sector,patterns,maxpatts,dcPatterns,nDC,nTSP);
                   delete patterns;
                }
+               if(nDC>=maxpatts) break;
             }
-            // read patterns for the smallest coverage
-            // these patterns will partially fit into the bank
-            for(std::set<int>::const_iterator sectorPtr=
-                   (*iPartition).fSectorSet.begin();
-                sectorPtr!=(*iPartition).fSectorSet.end();sectorPtr++) {
-               int sector=*sectorPtr;
-               if(loadedSectorList.find(sector)==loadedSectorList.end()) {
-                  if((int)loadedSectorList.size()>=maxNumSector) continue;
-                  loadedSectorList.insert(sector);
-               }
-               FTKPatternOneSector *patterns=TSPreader->Read(sector,covEnd);
-               if(patterns) {
-                  insertPatterns(sector,patterns,maxpatts,dcPatterns,nDC,nTSP);
-                  delete patterns;
-                  if(nDC>=maxpatts) break;
+            Info("readSectorOrderedBank")
+               <<"added coverage range "<<covBegin<<"-"<<covEnd
+               <<" DC added="<<nDC-nDCold
+               <<" TSP used="<<nTSP-nTSPold<<"/"<<nAvail
+               <<"\n";
+            if(nDC>=maxpatts){ 
+               if((nTSP-nTSPold<nAvail)||(i!=coverageMap.rend())) {
+                  tooFew=false;
                }
+               break;
             }
-            i=j;
-             // stop if all patterns have been read
+            // stop if all patterns have been read
             // or if the maximum number of patterns is reached
 
-            // DEBUG - speed up parttern reading
+            // for DEBUGGING - speed up pattern reading
             //   break;
 
-         } while((i!=coverageMap.rend())&&(nDC<maxpatts));
+         }
+         for(std::set<int>::const_iterator sectorPtr=
+                (*iPartition).fSectorSet.begin();
+             sectorPtr!=(*iPartition).fSectorSet.end();sectorPtr++) {
+            int sector=*sectorPtr;
+            m_tooFew[sector]=tooFew;
+         }
          Info("readSectorOrderedBank")
             <<"partition "<<partitionCount<<" number of DC patterns: "<<nDC-nDC0
+            <<"/"<<maxpatts-nDC0
             <<" smallest coverage="<<covEnd
             <<" #sectors="<<loadedSectorList.size()
             <<" maxnsector="<<maxNumSector
+            <<" tooFew="<<tooFew
+            <<" nDC="<<nDC
             <<"\n";
          partitionCount++;
          sectorCount += loadedSectorList.size();
@@ -3695,6 +3337,7 @@ int FTK_CompressedAMBank::readPartitionedSectorOrderedBank
          pos += dcPatterns[sector].size()*offsetSSID;
          numPattern+=dcPatterns[sector].size();
       }
+      Info("readSectorOrderedBank")<<"numPattern="<<numPattern<<"\n";
       int32_t *ssidData=new int32_t[pos];
       for(unsigned sector=0;sector<dcPatterns.size();sector++) {
          HitPatternMap_t const &hitMap=dcPatterns[sector];
@@ -3782,17 +3425,7 @@ void FTK_CompressedAMBank::clear(void) {
 void FTK_CompressedAMBank::sort_hits
 (const std::vector<FTKHit> &hits) {
    // list of all hits, ordered by layer and TSP-SSID
-#ifdef INTERNAL_LIST
-   // list of hits
-   typedef std::list<FTKHit const *> SSinfo_t;
-   // first: TSP-SSID, second: pair<dc-ssid,hits>
-   typedef MAP<int,SSinfo_t> SSinfoBySSID_t;
-   // for each plane
-   typedef std::vector<SSinfoBySSID_t> SSinfoByLayerSSID_t;
-   SSinfoByLayerSSID_t hitList(getNPlanes());
-#else
    std::vector< std::set<int> > tsp_ss_set(getNPlanes());
-#endif
    // layers where all hits shall be skipped
    int layerMask=FTKSetup::getFTKSetup().getMaskLayers();
 
@@ -3872,20 +3505,6 @@ void FTK_CompressedAMBank::sort_hits
          }
       }
 
-#ifdef INTERNAL_LIST
-      // check whether this TSP-SSID is new or not
-      SSinfoBySSID_t::iterator iSSID=hitList[iplane].find(coded_ssid);
-      if(iSSID==hitList[iplane].end()) {
-         // this SSID has not been entered yet
-         iSSID=hitList[iplane].insert
-            (std::make_pair(coded_ssid,std::list<FTKHit const *>())).first;
-         m_tspSSID[iplane].push_back(tsp_ssid);
-      }
-      // add hit
-      (*iSSID).second.push_back(hit);
-      //cout<<"P"<<iplane<<" SSID="<<coded_ssid<<" nhit="
-      //    <<(*iSSID).second.size()<<"\n";
-#else
       std::unordered_map<int,FTKSS>::iterator
          ssPtr=m_FiredSSmap[iplane].insert
          (std::make_pair(coded_ssid,FTKSS())).first;
@@ -3901,29 +3520,12 @@ void FTK_CompressedAMBank::sort_hits
                <<" highres="<<(coded_ssid & ((1<<m_TSPmap->getNBits(iplane))-1))
                <<" nhit="
                <<(*ssPtr).second.getNHits()<<"\n"; */
-#endif
    }
    if(error) {
       Warning("sort_hits")<<"failed to calculate SSID for "<<error<<"/"
                         <<expectedNHit<<" FTKHits\n";
    }
    for (int ipl=0;ipl<getNPlanes();++ipl) {
-#ifdef INTERNAL_LIST
-      SSinfoBySSID_t &hitsInLayer=hitList[ipl];
-      MAP<int,std::vector<FTKSS> > firedTSPbyDC;
-      for(SSinfoBySSID_t::const_iterator iSSID=hitsInLayer.begin();
-          iSSID!=hitsInLayer.end();iSSID++) {
-         int coded_ss=(*iSSID).first;
-         std::list<FTKHit const *> const &hits=(*iSSID).second;
-         std::unordered_map<int,FTKSS>::iterator
-            ssPtr=m_FiredSSmap[ipl].insert
-            (std::make_pair(coded_ss,FTKSS())).first;
-         for(std::list<FTKHit const *>::const_iterator ihit=
-                hits.begin();ihit!=hits.end();ihit++) {
-            (*ssPtr).second.addHit(**ihit);
-         }
-      }
-#endif
       naoSSPushBack(m_FiredSSmap[ipl].size());
    }
    // statistics
@@ -3939,11 +3541,9 @@ void FTK_CompressedAMBank::data_organizer(void) {
 
 void FTK_CompressedAMBank::data_organizer_r
 (std::vector<std::list<int> > const &tspSSIDfired) {
-   int maxSector=0;
-   if(m_SectorFirstLastPattern.rbegin()!=m_SectorFirstLastPattern.rend())
-      maxSector=(*m_SectorFirstLastPattern.rbegin()).first+1;
+   int maxSector=m_bank.m_PatternRangeBySector.size();
    m_sectorUsage.resize(maxSector);
-   memset(m_sectorUsage.data(),0,sizeof(HitPattern_t)*m_sectorUsage.size());
+   memset(m_sectorUsage.data(),0,sizeof(FTK_HitMask)*m_sectorUsage.size());
    //
    // loop over all input (layer,ssid)
    // locate the (layer,ssid) in the bank
@@ -3951,7 +3551,7 @@ void FTK_CompressedAMBank::data_organizer_r
    //    patternDataBySectorLayerSSID[sector][layer][ssid]
    for(int iplane=0;iplane<getNPlanes();iplane++) {
       LayerData const &bankDataThisLayer=m_bank.m_PatternByLayer[iplane];
-      HitPattern_t mask=1<<iplane;
+      FTK_HitMask mask=1<<iplane;
       for(std::list<int>::const_iterator iSSID=tspSSIDfired[iplane].begin();
           iSSID!=tspSSIDfired[iplane].end();iSSID++) {
          int tsp_ssid=(*iSSID);
@@ -3961,9 +3561,9 @@ void FTK_CompressedAMBank::data_organizer_r
          if(ssidInBank!=bankDataThisLayer.m_SSidData.end()) {
             // tsp_ssid is present in the pattern bank
             //  loop over all its sectors and set mask
-            for(PatternBySector_t::const_ptr sector=
-                   (*ssidInBank).second.beginPtr();
-                sector!=(*ssidInBank).second.endPtr();++sector) {
+            for(FTK_CompressedSectorPatternList::const_iterator sector=
+                   (*ssidInBank).second.begin();
+                sector!=(*ssidInBank).second.end();++sector) {
                m_sectorUsage[(*sector).first]|=mask;
             }
          }
@@ -3971,13 +3571,12 @@ void FTK_CompressedAMBank::data_organizer_r
    }
    //
    // loop over all sectors
-   // discard sectors with insufficient number of hits candidates
-   for(MAP<int,std::pair<int,int> >::const_iterator isector=
-          m_SectorFirstLastPattern.begin();
-       isector!=m_SectorFirstLastPattern.end();isector++) {
-      int sector=(*isector).first;
+   for(size_t sector=0;sector<m_bank.m_PatternRangeBySector.size();sector++) {
+      Range const &range=m_bank.m_PatternRangeBySector[sector];
+      // skip empty sectors
+      if(!range.Size()) continue;
       // determine wildcard for this sector
-      HitPattern_t sectorWildcard=m_SectorWC[sector];
+      FTK_HitMask sectorWildcard=m_SectorWC[sector];
       int hitPattern=m_sectorUsage[sector] | sectorWildcard;
       int nhit=m_nHit16[hitPattern];
 #ifdef DEBUG_EVENT
@@ -3996,17 +3595,10 @@ void FTK_CompressedAMBank::data_organizer_r
       if(nhit>=m_nhWCmin) {
          //
          // reset hit pattern for this sector
-         int firstPattern=(*isector).second.first;
-         int lastPattern=(*isector).second.second;
+         int firstPattern=range.First();
+         int lastPattern=range.Last();
          if(firstPattern<=lastPattern) {
-            if(sizeof(HitPattern_t)==1) {
-               memset(m_hitPatterns.data()+firstPattern,sectorWildcard,
-                      lastPattern+1-firstPattern);
-            } else {
-               for(int i=firstPattern;i<=lastPattern;i++) {
-                  m_hitPatterns[i]=sectorWildcard;
-               }
-            }
+            m_hitMask.init(firstPattern,lastPattern,sectorWildcard);
          }
       } else {
          // skip this sector
@@ -4029,111 +3621,141 @@ void FTK_CompressedAMBank::am_in(void) {
          } */
    am_in_r(m_tspSSID);
 }
-
+               
 void FTK_CompressedAMBank::am_in_r
 (std::vector<std::list<int> > const &tspSSIDfired) {
    // first part of the AM emulation
    //   corresponds to am_in()
    //   the hits are fed into the assiciated memory
    //   and road candidates are defined
-   class MaskUpdaterFast {
-      // fast update of hitpattern only
+
+   class MaskUpdateBase {
    public:
-      inline MaskUpdaterFast(HitPattern_t *hits,HitPattern_t msk)
-         : m_patternPtr(hits), m_mask(msk) {
-      }
-      inline void process(void) {
-         *m_patternPtr |= m_mask;
-      }
-      inline void update(int delta) {
-         m_patternPtr += delta;
-      }
-      inline void initialize(int firstPattern) {
-         update(firstPattern);
+      MaskUpdateBase
+      (FTK_HitMaskVector &hits,VECTOR<FTK_HitMask> const &sectorUsage,
+       uint8_t layer)
+         : m_hits(hits),m_sectorUsage(sectorUsage),m_layer(layer) { }
+      inline void update(uint32_t delta) { m_patternPtr.update(delta); }
+      inline void update4(uint32_t delta4) { m_patternPtr.update4(delta4); }
+      inline void init(uint32_t firstPattern) {
+         m_patternPtr =m_hits.getPointer(firstPattern);
+         m_patternPtr.setLayer(m_layer);
       }
    protected:
-      HitPattern_t * __restrict m_patternPtr;
-      HitPattern_t m_mask;
+      FTK_HitMaskVector &m_hits;
+      VECTOR<FTK_HitMask> const &m_sectorUsage;
+      FTK_HitMask m_layer;
+      FTK_HitMaskIterator m_patternPtr;
+   };
+//#define DEBUG_MASK_UPDATER
+   class MaskUpdaterFast : public MaskUpdateBase {
+      // update of hitpatterns without checking threshold
+   public:
+      inline MaskUpdaterFast
+      (FTK_HitMaskVector &hits,VECTOR<FTK_HitMask> const &sectorUsage,
+       uint8_t layer) : MaskUpdateBase(hits,sectorUsage,layer) { }
+      inline bool setSector(uint32_t sector) {
+         return m_sectorUsage[sector]!=0; }
+      inline void process(void) { m_patternPtr.process(); }
    };
-   class MaskUpdaterSlow {
-      // slow update:
-      // update hit pattern and
-      // determine road candidates
-      // a road candidate is stored if:
-      //   (1) the pattern has hits in other layers
-      //   (2) the pattern has no hit in the present layer
-      //   (3) the updated mask has exactly the minimum number of hits
-      // condition (1) is to skip empty patterns (not needed?)
-      // condition (2) is to ensure a valid pattern is stored only once
-      // condition (3) is there to ensure the pattern is there and stored only
-      //   as the threshold is passed
+   class MaskUpdaterSlow : public MaskUpdateBase {
+      // update of hitpatterns
+      // if hit threshold is passed, save road candidate
    public:
-      inline MaskUpdaterSlow(HitPattern_t *hits,HitPattern_t msk,
-                             uint32_t sectorID,
-                             uint8_t nhmin,uint8_t const *nh16,
-                             VECTOR<
-                             std::pair<uint32_t,uint32_t>
-                             > &rc,unsigned &nrc)
-         : m_patternPtr(hits), m_mask(msk),m_notMask(~msk),m_roadCandidates(rc),
-           m_nRC(nrc),m_nhMin(nhmin),m_nhit16(nh16),m_sector(sectorID)
+      inline MaskUpdaterSlow
+      (FTK_HitMaskVector &hits,VECTOR<FTK_HitMask> const &sectorUsage,
+       uint8_t layer,uint8_t nhWCmin,
+#ifdef ROAD_CAND_AS_VECTOR
+       std::vector<std::pair<uint32_t,uint32_t> > &roadCand
+#else
+       VECTORMAP<uint32_t> &roadCandMap
+#endif
+       )
+         : MaskUpdateBase(hits,sectorUsage,layer),
+           m_nhWCmin(nhWCmin),
+#ifdef ROAD_CAND_AS_VECTOR
+           m_roadCand(roadCand)
+#else
+           m_roadCandMap(roadCandMap)
+#endif
       {
-         m_base=m_patternPtr;
+#ifdef DEBUG_MASK_UPDATER
+         m_nSector=0;
+         m_nProcess=0;
+         m_nProcess4=0;
+         m_nPass=0;
+         for(int i=0;i<4;i++) m_nPassX[i]=0;
+         m_nCheck=0;
+         m_nPassCheck=0;
+#endif
       }
+      inline bool setSector(uint32_t sector) {
+#ifdef DEBUG_MASK_UPDATER
+         m_nSector++;
+#endif
+         m_sector=sector;
+         return m_sectorUsage[sector]!=0; }
       inline void process(void) {
-         HitPattern_t h0=*m_patternPtr;
-         HitPattern_t h1=h0|m_mask;
-#ifdef DEBUG_EVENT
-         if(g_event==DEBUG_EVENT) {
-            std::cout<<m_patternPtr-m_base<<": 0x"<<std::setbase(16)
-                     <<(int)h0<<" -> "<<(int)h1
-                     <<std::setbase(10);
+#ifdef DEBUG_MASK_UPDATER
+         m_nProcess++;
+#endif
+         if(m_patternPtr.process()) {
+#ifdef DEBUG_MASK_UPDATER
+            m_nPass++;
+#endif
+            checkSaveRoad(0);
          }
+      }
+      inline void checkSaveRoad(int offset) {
+#ifdef DEBUG_MASK_UPDATER
+            m_nCheck++;
 #endif
-         if( // if there are hits in other layers
-            (h0 & m_notMask)&&
-            // if this is the first hit in this layer
-            (!(h0 & m_mask))&&
-            // if the number of hits is exactly at the threshold
-            (m_nhit16[h1]==m_nhMin)
-            ) {
-            if(m_nRC<m_roadCandidates.size()) {
-               m_roadCandidates[m_nRC++] =
-                  std::make_pair(m_patternPtr-m_base,m_sector)
-                  ;
-#ifdef DEBUG_EVENT
-               if(g_event==DEBUG_EVENT) {
-                  std::cout<<" >>> add roadCandidate";
-               }
+         if(m_patternPtr.getNHit(offset)==m_nhWCmin) {
+#ifdef DEBUG_MASK_UPDATER
+            m_nPassCheck++;
 #endif
+#ifdef ROAD_CAND_AS_VECTOR
+            if(m_roadCand.size()<m_roadCand.capacity()) {
+               uint32_t pattern=m_hits.getPatternID(m_patternPtr)+offset;
+               m_roadCand.push_back(std::make_pair(pattern,m_sector));
             }
-         }
-#ifdef DEBUG_EVENT
-         if(g_event==DEBUG_EVENT) {
-            std::cout<<"\n";
-         }
+#else
+            uint32_t pattern=m_hits.getPatternID(m_patternPtr)+offset;
+            m_roadCandMap[pattern]=m_sector;
 #endif
-         *m_patternPtr =h1;
-      }
-      inline void update(int delta) {
-         m_patternPtr += delta;
+         }
       }
-      inline void initialize(int firstPattern) {
-         update(firstPattern);
+#ifdef DEBUG_MASK_UPDATER
+      void print(void) const {
+         std::cout
+            <<"MaskUpdater L"<<(int)m_layer
+            <<" nSector="<<m_nSector
+            <<" nProcess="<<m_nProcess
+         std::cout<<" nCheck="<<m_nCheck<<" nPassCheck="<<m_nPassCheck
+                  <<"\n";
       }
+#endif
    protected:
-      HitPattern_t * __restrict  m_patternPtr,* __restrict  m_base;
-      HitPattern_t m_mask;
-      HitPattern_t m_notMask;
-      VECTOR<std::pair<uint32_t,uint32_t> > &m_roadCandidates;
-      unsigned &m_nRC;
-      uint8_t m_nhMin;
-      uint8_t const *m_nhit16;
+#ifdef DEBUG_MASK_UPDATER
+      uint32_t m_nSector,m_nProcess;
+      uint32_t m_nPass;
+      uint32_t m_nCheck,m_nPassCheck;
+#endif
       uint32_t m_sector;
+      uint8_t m_nhWCmin;
+#ifdef ROAD_CAND_AS_VECTOR
+      std::vector<std::pair<uint32_t,uint32_t> > &m_roadCand;
+#else
+      VECTORMAP<uint32_t> &m_roadCandMap;
+#endif
    };
-   m_nRoadCand=0;
-   for(int iplane=0;iplane<getNPlanes();++iplane) {
+#ifdef ROAD_CAND_AS_VECTOR
+   m_roadCand.resize(0);
+#else
+   m_roadCandMap.clear();
+#endif
+   for(int iplane=0;iplane<m_nhWCmin-1;++iplane) {
       LayerData const &bankDataThisLayer=m_bank.m_PatternByLayer[iplane];
-      HitPattern_t mask= 1<<iplane;
       for(std::list<int>::const_iterator iSSID=tspSSIDfired[iplane].begin();
           iSSID!=tspSSIDfired[iplane].end();iSSID++) {
          int tsp_ssid=(*iSSID);
@@ -4141,42 +3763,52 @@ void FTK_CompressedAMBank::am_in_r
          PatternBySectorSSidMap_t::const_iterator ssidInBank=
             bankDataThisLayer.m_SSidData.find(tsp_ssid);
          if(ssidInBank!=bankDataThisLayer.m_SSidData.end()) {
-            // tsp_ssid is present in the pattern bank
-            //  loop over all its sectors and set mask
-            for(PatternBySector_t::const_ptr isector=
-                   (*ssidInBank).second.beginPtr();
-                isector!=(*ssidInBank).second.endPtr();++isector) {
-               int sector=(*isector).first;
-               if(!m_sectorUsage[sector]) continue;
-               SectorData const &sectorData((*isector).second);
-               // determine threshold for slow update
-               int hitMin=m_nhWCmin-m_nHit16[m_SectorWC[sector]]-1;
-               if(iplane<hitMin) {
-                  // first planes: no chance to form a road candidate
-                  // simply update bit mask
-                  MaskUpdaterFast updater(m_hitPatterns.data(),mask);
-                  patternLoop(updater,
-                              m_bank.m_PatternByLayer[iplane].
-                              m_CompressedDeltaBySector[sector].data()+
-                              sectorData.m_offset,
-                              sectorData.m_FirstPattern,sectorData.m_NPattern);
-               } else {
-                  // last planes, update bit mask and remember road candidates
-                  MaskUpdaterSlow updater
-                     (m_hitPatterns.data(),mask,
-                      sector,
-                      m_nhWCmin,m_nHit16.data(),
-                      m_roadCand,m_nRoadCand);
-                  patternLoop(updater,
-                              m_bank.m_PatternByLayer[iplane].
-                              m_CompressedDeltaBySector[sector].data()+
-                              sectorData.m_offset,
-                              sectorData.m_FirstPattern,sectorData.m_NPattern);
-               }
-            }
+            MaskUpdaterFast updater(m_hitMask,m_sectorUsage,iplane);
+            (*ssidInBank).second.patternLoop(updater);
+         }
+      }
+   }
+   for(int iplane=m_nhWCmin-1;iplane<getNPlanes();++iplane) {
+      LayerData const &bankDataThisLayer=m_bank.m_PatternByLayer[iplane];
+#ifdef DEBUG_MASK_UPDATER
+      MaskUpdaterSlow updater(m_hitMask,m_sectorUsage,iplane,
+                              m_nhWCmin,
+#ifdef ROAD_CAND_AS_VECTOR
+                              m_roadCand
+#else
+                              m_roadCandMap
+#endif
+                              );
+#endif
+      for(std::list<int>::const_iterator iSSID=tspSSIDfired[iplane].begin();
+          iSSID!=tspSSIDfired[iplane].end();iSSID++) {
+         int tsp_ssid=(*iSSID);
+         // locate the SSID in the pattern bank
+         PatternBySectorSSidMap_t::const_iterator ssidInBank=
+            bankDataThisLayer.m_SSidData.find(tsp_ssid);
+         if(ssidInBank!=bankDataThisLayer.m_SSidData.end()) {
+#ifndef DEBUG_MASK_UPDATER
+            MaskUpdaterSlow updater(m_hitMask,m_sectorUsage,iplane,
+                                    m_nhWCmin,
+#ifdef ROAD_CAND_AS_VECTOR
+                                    m_roadCand
+#else
+                                    m_roadCandMap
+#endif
+                                    );
+#endif
+            (*ssidInBank).second.patternLoop(updater);
          }
       }
+#ifdef DEBUG_MASK_UPDATER
+      updater.print();
+#endif
    }
+#ifdef DEBUG_MASK_UPDATER
+   std::cout<<"Road Candidates: "<<m_roadCand.size()
+            <<" / "<<m_roadCand.capacity()<<"\n";
+   exit(86);
+#endif
 }
 
 /**
@@ -4185,15 +3817,43 @@ void FTK_CompressedAMBank::am_in_r
    Output: populate m_roads
  */
 
+#ifdef ROAD_CAND_AS_VECTOR
+static int roadCandSorter(const void *a,const void *b) {
+   std::pair<uint32_t,uint32_t> const *pairA=
+      (std::pair<uint32_t,uint32_t> const *)(a);
+   std::pair<uint32_t,uint32_t> const *pairB=
+      (std::pair<uint32_t,uint32_t> const *)(b);
+   if((*pairA).first<(*pairB).first) return -1;
+   if((*pairA).first>(*pairB).first) return 1;
+   return 0;
+}
+#endif
+
 void FTK_CompressedAMBank::am_output() {
-   for(unsigned iCand=0;iCand<m_nRoadCand;iCand++) {
+#ifdef ROAD_CAND_AS_VECTOR
+   qsort(m_roadCand.data(),m_roadCand.size(),
+         sizeof(std::pair<uint32_t,uint32_t>),roadCandSorter);
+#endif
+   const FTKPlaneMap *pmap = getSSMapTSP()->getPlaneMap();
+   for(
+#ifdef ROAD_CAND_AS_VECTOR
+       unsigned iCand=0;iCand<m_roadCand.size();
+#else
+       VECTORMAP<uint32_t>::const_iterator iCand=m_roadCandMap.begin();
+       iCand!=m_roadCandMap.end();
+#endif
+       iCand++) {
+#ifdef ROAD_CAND_AS_VECTOR
       int patternID=m_roadCand[iCand].first;
       int sector=m_roadCand[iCand].second;
+#else
+      int patternID=(*iCand).first;
+      int sector=(*iCand).second;
+#endif
 
-      const FTKPlaneMap *pmap = getSSMapTSP()->getPlaneMap();
-
-      HitPattern_t hitmaskWithWC=m_hitPatterns[patternID];
-      HitPattern_t hitmaskNoWC=hitmaskWithWC & ~m_SectorWC[sector];
+      FTK_HitMask hitmaskWithWC =
+         m_hitMask.getPointer(patternID).getHitMask();
+      FTK_HitMask hitmaskNoWC=hitmaskWithWC & ~m_SectorWC[sector];
       uint8_t nhWC=m_nHit16[hitmaskWithWC];
 #ifdef DEBUG_EVENT
       if(g_event==DEBUG_EVENT) {
@@ -4262,49 +3922,50 @@ void FTK_CompressedAMBank::am_output() {
             road.setPatternDBID(patternID);
             //
             // unpack DC bits and DC-SSID from pattern bank
-            int dcMask=0,hbmask=0;
+            int dcmask=0,hbmask=0;
+            //
+            // vallidate pattern ID
+            Range const &sectorRange=m_bank.m_PatternRangeBySector[sector];
+            if((patternID<sectorRange.First())||(patternID>sectorRange.Last())) {
+               Fatal("am_out")
+                  <<"mismatch sector "<<sector
+                  <<" ["<<sectorRange.First()<<","<<sectorRange.Last()<<"]"
+                  <<" pattern "<<patternID<<"\n";
+            }
             //
             // loop over all planes
             for (int ipl=getNPlanes()-1;ipl>=0;--ipl) {
                int nDCbits=m_TSPmap->getNBits(ipl);
-               int nDCHBbits=2*nDCbits;
-               //
-               // dcSSID_with_DCbits contains
-               //   the encoded SSID-index and the encoded DC bits
-               // nbit=nDCHBbits
-               //              <-- nbit -->
-               //  MSB..................LSB
-               // ------------+-------------
-               //   SSIDindex |   DCbits
-               unsigned dcSSID_with_DCbits;
-               if(m_bank.m_pattern8Data[ipl].size()) {
-                  dcSSID_with_DCbits=m_bank.m_pattern8Data[ipl][patternID];
-               } else {
-                  dcSSID_with_DCbits=m_bank.m_pattern16Data[ipl][patternID];
+               // extract DC SSID
+               int dcSSID=m_bank.m_PatternByLayer[ipl].
+                  m_SSIDternaryByPattern.getSSID(sector,patternID);
+               // extract DC and HB bits
+               std::pair<uint16_t,uint16_t> dchb=m_bank.m_PatternByLayer[ipl].
+                  m_SSIDternaryByPattern.getDCHB(patternID);
+               hbmask = (hbmask<<nDCbits)|dchb.second;
+               dcmask = (dcmask<<nDCbits)|dchb.first;
+
+               // construct sub-mask
+               // this is a bit-array
+               // bit number N is set if an SSID with the least-significant
+               //   bits equal to N is valid, given teh DC and HB bits
+               uint16_t zeroIsValid=dcmask|~hbmask;
+               uint16_t oneIsValid=dcmask|hbmask;
+               uint32_t subMask=1;
+               int pos=1;
+               for(int bit=0;bit<nDCbits;bit++) {
+                  uint16_t mask=1<<bit;
+                  subMask=
+                     ((zeroIsValid & mask) ? subMask : 0) |
+                     ((oneIsValid & mask) ? (subMask<<pos) : 0);
+                  pos<<=1;
                }
-               //
-               // decode SSID using index table:
-               //   m_bank.m_PatternByLayer[ipl].m_dcSSIDtable[sector]
-               int dcSSIDindex=dcSSID_with_DCbits >> nDCHBbits;
-               int dcSSID=m_bank.m_PatternByLayer[ipl].m_dcSSIDbySectorIndex
-                  [sector][dcSSIDindex];
-               //
-               //
-               // decode DC and HB bits
-               int dcBits=dcSSID_with_DCbits & ((1<<nDCHBbits)-1);
-               dcMask =(dcMask<<nDCbits) | m_dcMaskLookup[ipl][dcBits];
-               hbmask =(hbmask<<nDCbits) | m_hbMaskLookup[ipl][dcBits];
-               // store SSID
-               //2016/01/15 Guido's new format (???)
-               //if(sectorWildcard & (1<<ipl)) {
-                  // wildcard
-               // road.setSSID(ipl,m_WCID);
-               //} else {
+               // set up road
                int roadSSID=-1;
                if(dcSSID>=0) {
 #ifdef HW2_USE_TSPMAP
                   roadSSID=(dcSSID<<nDCbits)|
-                     (hbmask & (~dcMask) & ((1<<nDCbits)-1));
+                     (hbmask & (~dcmask) & ((1<<nDCbits)-1));
 #else
                   roadSSID=(dcSSID<<nDCbits)|
                      (hbmask & (~dcMask) & ((1<<nDCbits)-1));
@@ -4313,21 +3974,21 @@ void FTK_CompressedAMBank::am_output() {
                   roadSSID=dcSSID;
                }
                road.setSSID(ipl,roadSSID);  //attachSS[ 655 -> 670]
-               // }
                //
                // store subss mask
-               road.setSubSSMask(ipl,m_subSSmask[ipl][dcBits]);
+               road.setSubSSMask(ipl,subMask);
                //
                // set HLID (?)  - see FTKTSPBank::attachSS()
                road.setHLID(ipl,m_TSPmap->getNBits(ipl));
             }
             //
             // store ternary bits
-            road.setDCBitmask(dcMask);
+            road.setDCBitmask(dcmask);
             road.setHLBitmask(hbmask);
          }
       }
    }
+   // std::cout<<"Number of roads: "<<getNRoads()<<"\n";
    naoSetNroadsAM(getNRoads());
    naoSetNroadsAMComplete(getNRoads_complete());
    naoSetNroadsAMMissPix(getNRoads_misspix());
@@ -4427,7 +4088,8 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
       int dcMask=(*iroad).getDCBitmask();
       // HB mask: if bit is set: bit takes value [0|1]
       int hbMask=(*iroad).getHLBitmask();
-      for (int ipl=0;(ipl<getNPlanes())&&(!getStoreAllSS());++ipl) {
+      int roadError=0;
+      for (int ipl=0;ipl<getNPlanes();++ipl) {
          int nDCbits=m_TSPmap->getNBits(ipl);
          // bitMask: set to one for all positions with ternary bits
          int bitMask=(1<<nDCbits)-1;
@@ -4438,7 +4100,7 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
          // mask out all ternary bits
          int nodc_ssid=(*iroad).getSSID(ipl);
          int found=0;
-         for(int bits=0;bits<(1<<nDCbits);bits++) {
+         for(int bits=0;bits<=bitMask;bits++) {
             // skip ternary bit combinations if HB bits are not properly set
             if( (bits & isHB) != hb) continue;
             std::unordered_map<int,FTKSS>::iterator item0 =
@@ -4446,34 +4108,24 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
             if (item0==m_FiredSSmap[ipl].end()) 
                continue; // no hits
             // map for this plane
-            std::unordered_map<int,FTKSS> &imap = m_UsedSSmap[ipl];
-            // find this ss is in the bank
-            std::unordered_map<int,FTKSS>::iterator item =
-               imap.find(nodc_ssid|bits);
-            if (item==imap.end()) { // not found
-               imap[nodc_ssid|bits] = (*item0).second;
+            if(!getStoreAllSS()) {
+               std::unordered_map<int,FTKSS> &imap = m_UsedSSmap[ipl];
+               // if requested, find this ss is in the bank
+               std::unordered_map<int,FTKSS>::iterator item =
+                  imap.find(nodc_ssid|bits);
+               if (item==imap.end()) { // not found
+                  imap[nodc_ssid|bits] = (*item0).second;
+               }
+               naoClusRoadAdd(ipl,(imap[nodc_ssid|bits]).getNHits());
             }
-	    naoClusRoadAdd(ipl,(imap[nodc_ssid|bits]).getNHits());
-
             found++;
          }
+         /*if((*iroad).getPatternID()==15441589) {
+            std::cout<<"road pattern="<<(*iroad).getPatternID()
+                     <<" plane="<<ipl<<" found="<<found<<"\n";
+                     } */
          if((*iroad).hasHitOnLayer(ipl) && !found) {
-            Error("getRoads")
-               <<"Plane="<<ipl<<" no fired SS found, ssid="
-               <<(nodc_ssid>>nDCbits)
-               <<" pattern="<<(*iroad).getPatternID()<<"\n";
-            std::vector<int> const &ssid_with_dcbits=getTSPssidVector
-               (ipl,(*iroad).getSectorID(),nodc_ssid>>nDCbits);
-            std::cout<<"DC="<<(nodc_ssid>>nDCbits)<<" -> TSP=[";
-            for(size_t i=0;i<ssid_with_dcbits.size();i++) {
-               std::cout<<" "<<ssid_with_dcbits[i];
-            }
-            std::cout<<"]\n";
-            std::cout<<"nDCbits="<<nDCbits<<" bitMask="<<bitMask
-                     <<" isHB="<<isHB<<" hb="<<hb<<"\n";
-            error++;
-            errorSector=(*iroad).getSectorID();
-            errorPattern=(*iroad).getPatternID();
+            roadError++;
          }
          // begin debugging
          // if((*iroad).getPatternID()==2113347) error++;
@@ -4481,6 +4133,11 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
          dcMask>>=nDCbits;
          hbMask>>=nDCbits;
       } // end loop over the layers
+      if(roadError) {
+         errorSector=(*iroad).getSectorID();
+         errorPattern=(*iroad).getPatternID();
+         error++;
+      }
    }
    if(error) {
       printRoads(m_roads,/* -1 */ errorSector);
@@ -4488,7 +4145,6 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
       printSector(errorSector,2,errorPattern);
       throw FTKException("FTK_CompressedAMBank::getRoads inconsistency in SSID numbering");
    }
-
    // //JAAA now add number of hits in each plane within a road for dataflow
    // for (int ipl = 0; ipl<getNPlanes(); ipl++) { // loop over planes
    //   for(std::unordered_map<int,FTKSS>::const_iterator is=
@@ -4498,21 +4154,25 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
    //   }
    // }
 
-
-  static int print=PRINT_DETAILS_NEVENT;
+#ifdef PRINT_ROADSUMMARY_NEVENT
+  static int print=PRINT_ROADSUMMARY_NEVENT;
   if(print) {
      Info("getRoads")<<"number of roads="<<m_roads.size()<<"\n";
+#ifdef PRINT_DETAILS_NEVENT
      printRoads(m_roads,PRINT_ROADS_SECTORID);
+#endif
      Info("getRoads")
-        <<"number of strips fired"
-        <<" "<< m_FiredSSmap[0].size()
-        <<" "<< m_FiredSSmap[1].size()
-        <<" "<< m_FiredSSmap[2].size()
-        <<" "<< m_FiredSSmap[3].size()
-        <<" "<< m_FiredSSmap[4].size()
-        <<" "<< m_FiredSSmap[5].size()
-        <<" "<< m_FiredSSmap[6].size()
-        <<" "<< m_FiredSSmap[7].size()<<"\n";
+        <<"storeAllSS="<<getStoreAllSS()
+        <<" number of strips fired"
+        <<" "<< m_UsedSSmap[0].size()<<"/"<< m_FiredSSmap[0].size()
+        <<" "<< m_UsedSSmap[1].size()<<"/"<< m_FiredSSmap[1].size()
+        <<" "<< m_UsedSSmap[2].size()<<"/"<< m_FiredSSmap[2].size()
+        <<" "<< m_UsedSSmap[3].size()<<"/"<< m_FiredSSmap[3].size()
+        <<" "<< m_UsedSSmap[4].size()<<"/"<< m_FiredSSmap[4].size()
+        <<" "<< m_UsedSSmap[5].size()<<"/"<< m_FiredSSmap[5].size()
+        <<" "<< m_UsedSSmap[6].size()<<"/"<< m_FiredSSmap[6].size()
+        <<" "<< m_UsedSSmap[7].size()<<"/"<< m_FiredSSmap[7].size()<<"\n";
+#ifdef PRINT_DETAILS_NEVENT
      for(int ipl=0;ipl<getNPlanes();ipl++) {
         Info("getRoads")<<"number of strips in plane "<<ipl
                         <<" is "<< m_UsedSSmap[ipl].size()<<"\n";
@@ -4530,7 +4190,7 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
                  ->getLocalId(getBankID(),ipl,moduleID)
                        <<" x="<<hit[0];
               if(ipl<3) std::cout<<" y="<<hit[1];
-              std::cout<<"\n";
+              std::cout<<"\n";;
               for(int imap=0;imap<3;imap++) {
                  FTKSSMap *ssmap=getSSMapTSP();
                  if(imap==2) ssmap=getSSMap();
@@ -4559,8 +4219,10 @@ const std::list<FTKRoad>& FTK_CompressedAMBank::getRoads() {
            }
         }
      }
+#endif
      print--;
   }
+#endif
 #ifdef DEBUG_EVENT
   if(g_event==DEBUG_EVENT) {
      printStrips(-1);
@@ -4625,6 +4287,7 @@ void FTK_CompressedAMBank::printStrips(int printPlane) const {
         std::cout<<"]";
      }
      std::cout<<"\n";
+#ifdef PRINT_SS_DETAIL
      for(std::unordered_map<int,FTKSS>::const_iterator 
             is=m_FiredSSmap[plane].begin();
          is!=m_FiredSSmap[plane].end();is++) {
@@ -4637,7 +4300,7 @@ void FTK_CompressedAMBank::printStrips(int printPlane) const {
               ->getLocalId(getBankID(),plane,moduleID)
                     <<" xHW="<<hit.getHwCoord(0)<<" x="<<hit[0];
            if(plane<3) std::cout<<" yHW="<<hit.getHwCoord(1)<<" y="<<hit[1];
-           std::cout<<"\n";
+           std::cout<<"\n";;
            for(int imap=0;imap<3;imap++) {
               FTKSSMap *ssmap=getSSMapTSP();
               if(imap==2) ssmap=getSSMap();
@@ -4665,6 +4328,7 @@ void FTK_CompressedAMBank::printStrips(int printPlane) const {
            }
         }
      }
+#endif
    }
 }
 
@@ -4677,16 +4341,15 @@ void FTK_CompressedAMBank::printStrips(int printPlane) const {
 void FTK_CompressedAMBank::printSector(int sector,int npattern,
                                        int ipattern) {
    std::cout<<" FTK_CompressedAMBank::printSector\n";
-   MAP<int,std::pair<int,int> >::const_iterator sectorPtr=
-      m_SectorFirstLastPattern.find(sector);
-   if(sectorPtr!=m_SectorFirstLastPattern.end()) {
+   Range const &range=m_bank.m_PatternRangeBySector[sector];
+   if(range.Size()) {
       std::cout<<" sector="<<sector<<" ["
-               <<(*sectorPtr).second.first<<","
-               <<(*sectorPtr).second.second<<"]\n";
+               <<range.First()<<","
+               <<range.Last()<<"]\n";
       int i0[2],i1[2];
       int npart=1;
-      i0[0]=(*sectorPtr).second.first;
-      i1[0]=(*sectorPtr).second.second;
+      i0[0]=range.First();
+      i1[0]=range.Last();
       if(i1[0]-i0[0]+1>npattern) {
          i1[1]=i1[0];
          i1[0]=i0[0]+npattern/2-1;
@@ -4703,10 +4366,8 @@ void FTK_CompressedAMBank::printSector(int sector,int npattern,
                npart=1;
                i0[0]=ipattern-npattern/2;
                i1[0]=ipattern+npattern/2;
-               if(i0[0]<(*sectorPtr).second.first)
-                  i0[0]=(*sectorPtr).second.first;
-               if(i1[0]>(*sectorPtr).second.second)
-                  i1[0]=(*sectorPtr).second.second;
+               if(i0[0]<range.First()) i0[0]=range.First();
+               if(i1[0]>range.Last()) i1[0]=range.Last();
             }
          }
       }
@@ -4731,33 +4392,17 @@ void FTK_CompressedAMBank::printSector(int sector,int npattern,
             int nmax=0;
             for(int ipl=0;ipl<getNPlanes();ipl++) {
                int nDCbits=m_TSPmap->getNBits(ipl);
-               int nDCHBbits=2*nDCbits;
-               unsigned dcSSID_with_DCbits;
-               if(m_bank.m_pattern8Data[ipl].size()) {
-                  dcSSID_with_DCbits=m_bank.m_pattern8Data[ipl][patternID];
-               } else {
-                  dcSSID_with_DCbits=m_bank.m_pattern16Data[ipl][patternID];
-               }
-               int dcBits=dcSSID_with_DCbits & ((1<<nDCHBbits)-1);
-               uint32_t submask= m_subSSmask[ipl][dcBits];
-               int imax=0;
-               while(submask) {
-                  if(submask&1) imax++;
-                  submask>>=1;
-               }
-               if(imax>nmax) nmax=imax;
-               int dcSSIDindex=dcSSID_with_DCbits >> nDCHBbits;
-               int dcSSID=m_bank.m_PatternByLayer[ipl].
-                  m_dcSSIDbySectorIndex[sector][dcSSIDindex];
-               int dcMask = m_dcMaskLookup[ipl][dcBits];
-               int hbmask = m_hbMaskLookup[ipl][dcBits];
+               int dcSSID=m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+                  getSSID(sector,patternID);
+               std::pair<uint16_t,uint16_t> dchb=m_bank.m_PatternByLayer[ipl].
+                  m_SSIDternaryByPattern.getDCHB(patternID);
                std::cout<<std::setw(7)<<dcSSID;
                if(nDCbits) {
                   std::cout<<"-";
                   for(int i=nDCbits-1;i>=0;i--) {
-                     if(dcMask & (1<<i)) {
+                     if(dchb.first & (1<<i)) {
                         std::cout<<"X";
-                     } else if(hbmask &(1<<i)) {
+                     } else if(dchb.second &(1<<i)) {
                         std::cout<<"1";
                      } else {
                         std::cout<<"0";
@@ -4770,26 +4415,21 @@ void FTK_CompressedAMBank::printSector(int sector,int npattern,
                std::cout<<"        ";
                for(int ipl=0;ipl<getNPlanes();ipl++) {
                   int nDCbits=m_TSPmap->getNBits(ipl);
-                  int nDCHBbits=2*nDCbits;
-                  unsigned dcSSID_with_DCbits;
-                  if(m_bank.m_pattern8Data[ipl].size()) {
-                     dcSSID_with_DCbits=m_bank.m_pattern8Data[ipl][patternID];
-                  } else {
-                     dcSSID_with_DCbits=m_bank.m_pattern16Data[ipl][patternID];
-                  }
-                  int dcSSIDindex=dcSSID_with_DCbits >> nDCHBbits;
-                  int dcSSID=m_bank.m_PatternByLayer[ipl].m_dcSSIDbySectorIndex
-                     [sector][dcSSIDindex];
-                  int dcBits=dcSSID_with_DCbits & ((1<<nDCHBbits)-1);
-                  uint32_t submask= m_subSSmask[ipl][dcBits];
-                  std::vector<int> const &tspSSID=
-                     getTSPssidVector(ipl,sector,dcSSID);
+                  int dcSSID=m_bank.m_PatternByLayer[ipl].
+                     m_SSIDternaryByPattern.getSSID(sector,patternID);
+                  std::pair<uint16_t,uint16_t> dchb=
+                     m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+                     getDCHB(patternID);
+                  std::vector<int> const &tspSSID=getTSPssidVector(ipl,dcSSID);
                   int isub=0;
                   unsigned ipos;
                   if(nDCbits) std::cout<<" ";
                   for(int i=0;i<nDCbits;i++) std::cout<<" ";
                   for(ipos=0;ipos<tspSSID.size();ipos++) {
-                     if(submask &1) {
+                     // check whether ipos is allowed, given HB and DC
+                     //   bit^HB  is non-zero if the HB bit matches
+                     //  (bit^HB)&~DC is zero if HB matches of if DC is set
+                     if(((ipos ^ dchb.second)& ~dchb.first)==0) {
                         if(isub==line) {
                            std::cout<<std::setw(7)<<tspSSID[ipos];
                            usedSSID[ipl].insert
@@ -4798,7 +4438,6 @@ void FTK_CompressedAMBank::printSector(int sector,int npattern,
                         }
                         isub++;
                      }
-                     submask>>=1;
                   }
                   if(ipos==tspSSID.size()) std::cout<<"       ";
                }
@@ -4823,24 +4462,19 @@ void FTK_CompressedAMBank::printSector(int sector,int npattern,
             std::cout<<std::setw(8)<<patternID;
             for(int ipl=0;ipl<getNPlanes();ipl++) {
                int nDCbits=m_TSPmap->getNBits(ipl);
-               int nDCHBbits=2*nDCbits;
-               unsigned dcSSID_with_DCbits;
-               if(m_bank.m_pattern8Data[ipl].size()) {
-                  dcSSID_with_DCbits=m_bank.m_pattern8Data[ipl][patternID];
-               } else {
-                  dcSSID_with_DCbits=m_bank.m_pattern16Data[ipl][patternID];
-               }
-               int dcSSIDindex=dcSSID_with_DCbits >> nDCHBbits;
-               int dcBits=dcSSID_with_DCbits & ((1<<nDCHBbits)-1);
-               int dcMask = m_dcMaskLookup[ipl][dcBits];
-               int hbmask = m_hbMaskLookup[ipl][dcBits];
-               std::cout<<std::setw(3)<<dcSSIDindex;
+               std::pair<uint16_t,uint16_t> dchb=
+                  m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+                  getDCHB(patternID);
+               std::cout<<std::setw(3)<<m_bank.m_PatternByLayer[ipl].
+                  m_SSIDternaryByPattern.getPackedData(patternID)/
+                  m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+                  m_offsetTernary;
                if(nDCbits) {
                   std::cout<<"-";
                   for(int i=nDCbits-1;i>=0;i--) {
-                     if(dcMask & (1<<i)) {
+                     if(dchb.first & (1<<i)) {
                         std::cout<<"X";
-                     } else if(hbmask &(1<<i)) {
+                     } else if(dchb.second &(1<<i)) {
                         std::cout<<"1";
                      } else {
                         std::cout<<"0";
@@ -4854,65 +4488,60 @@ void FTK_CompressedAMBank::printSector(int sector,int npattern,
       std::cout<<"DC-SSID translation tables for sector "<<sector<<"\n";
       std::cout<<"=L=size======================data=====================================\n";
       for(int ipl=0;ipl<getNPlanes();ipl++) {
-         int n=m_bank.m_PatternByLayer[ipl].m_dcSSIDbySectorIndex[sector]
-            .size();
+         int n=m_bank.m_PatternByLayer[ipl].m_SSIDternaryByPattern.
+            m_dcSSIDbySectorIndex[sector].size();
          std::cout<<" "<<ipl<<std::setw(5)<<n<<" [";
          if(n<8) {
             for(int j=0;j<n;j++) {
                std::cout<<" "<<m_bank.m_PatternByLayer[ipl].
-                  m_dcSSIDbySectorIndex[sector][j];
+                  m_SSIDternaryByPattern.m_dcSSIDbySectorIndex[sector][j];
             }
          } else {
             for(int j=0;j<4;j++) {
                std::cout<<" "<<m_bank.m_PatternByLayer[ipl].
-                  m_dcSSIDbySectorIndex[sector][j];
+                  m_SSIDternaryByPattern.m_dcSSIDbySectorIndex[sector][j];
             }
             std::cout<<" ...";
             for(int j=n-4;j<n;j++) {
                std::cout<<" "<<m_bank.m_PatternByLayer[ipl].
-                  m_dcSSIDbySectorIndex[sector][j];
+                  m_SSIDternaryByPattern.m_dcSSIDbySectorIndex[sector][j];
             }
          }
          std::cout<<" ]\n";
       }
       std::cout<<"relevant part of compressed lookup-tables\n";
-      std::cout<<"=L===SSID=sector===first=npatt=nbyte==========data=====================\n";
+      std::cout<<"=L===SSID=sector===first=npatt=nbyte=encod==========data=====================\n";
       for(int ipl=0;ipl<getNPlanes();ipl++) {
          for(MAP<int,int>::const_iterator iSSID=usedSSID[ipl].begin();
              iSSID!=usedSSID[ipl].end();iSSID++) {
             PatternBySectorSSidMap_t::const_iterator jSSID=
                m_bank.m_PatternByLayer[ipl].m_SSidData.find((*iSSID).first);
             if(jSSID!=m_bank.m_PatternByLayer[ipl].m_SSidData.end()) {
-               PatternBySector_t::const_iterator jSector=
+               FTK_CompressedSectorPatternList::const_iterator jSector=
                   (*jSSID).second.find((*iSSID).second);
                if(jSector != (*jSSID).second.end()) {
+                  Int_t firstPattern,nPattern,encoding;
+                  std::vector<Int_t> deltaData;
+                  (*jSector).second.exportData
+                     (&firstPattern,&nPattern,&encoding,deltaData);
                   std::cout<<" "<<ipl<<std::setw(7)<<(*iSSID).first
                            <<std::setw(6)<<sector
-                           <<std::setw(8)<<(*jSector).second.m_FirstPattern
-                           <<std::setw(6)<<(*jSector).second.m_NPattern
-                           <<std::setw(6)<<(*jSector).second.m_length
+                           <<std::setw(8)<<firstPattern
+                           <<std::setw(6)<<nPattern
+                           <<std::setw(6)<<encoding
+                           <<std::setw(6)<<deltaData.size()
                            <<" ["<<std::setbase(16);
-                  if((*jSector).second.m_length<6) {
-                     for(unsigned k=0;k<(*jSector).second.m_length;k++) {
-                        std::cout
-                           <<" 0x"<<(int)m_bank.m_PatternByLayer[ipl].
-                           m_CompressedDeltaBySector[(*jSector).first]
-                           [(*jSector).second.m_offset+k];
+                  if(deltaData.size()<6) {
+                     for(unsigned k=0;k<deltaData.size();k++) {
+                        std::cout<<" 0x"<<deltaData[k];
                      }
                   } else {
                      for(int k=0;k<3;k++) {
-                        std::cout
-                           <<" 0x"<<(int)m_bank.m_PatternByLayer[ipl].
-                           m_CompressedDeltaBySector[(*jSector).first]
-                           [(*jSector).second.m_offset+k];
+                        std::cout<<" 0x"<<deltaData[k];
                      }
                      std::cout<<" ...";
-                     for(unsigned k=(*jSector).second.m_length-3;
-                         k<(*jSector).second.m_length;k++) {
-                        std::cout
-                           <<" 0x"<<(int)m_bank.m_PatternByLayer[ipl].
-                           m_CompressedDeltaBySector[(*jSector).first]
-                           [(*jSector).second.m_offset+k];
+                     for(unsigned k=deltaData.size()-3;k<deltaData.size();k++) {
+                        std::cout<<" 0x"<<deltaData[k];
                      }
                   }
                   std::cout<<std::setbase(10)<<" ]\n";
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedPatternList.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedPatternList.cxx
new file mode 100644
index 000000000000..2dd5f94d2e45
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedPatternList.cxx
@@ -0,0 +1,145 @@
+#include "TrigFTKSim/FTK_CompressedPatternList.h"
+#include <cstring>
+#include <iostream>
+#include <iomanip>
+#include <map>
+
+std::pair<uint32_t,uint32_t> FTK_CompressedPatternList::getMinMaxPattern(void)
+   const {
+   class GetMinMax : public FTK_CompressedPatternListLoopWithCounter_base {
+   public:
+      GetMinMax(void) { minMaxPattern.first=1; minMaxPattern.second=0; }
+      void process(void) {
+         if(minMaxPattern.first>minMaxPattern.second) {
+            minMaxPattern.first=getPattern();
+            minMaxPattern.second=getPattern();
+         } else {
+            minMaxPattern.second=getPattern(); 
+         }
+      }
+   std::pair<uint32_t,uint32_t> minMaxPattern;
+   } getMinMax;
+   patternLoop(getMinMax);
+   return getMinMax.minMaxPattern;
+}
+
+void FTK_CompressedPatternList::setData(uint32_t firstPattern,uint32_t encoding,
+                                        uint8_t const *dataPtr,uint32_t nData) {
+   m_FirstPattern=firstPattern;
+   m_encoding=encoding;
+   m_nData=nData;
+   m_loopHelper=0;
+   setDataPointer(dataPtr);
+   if(m_encoding==ENCODING_DELTA) {
+      // initialize loop helper, a trick to optimize the pattern loop
+      // (the loop is optimized by determining the (fixed) number of loops)
+      for(uint32_t i=0;i<m_nData;i++) {
+         if((m_data[i]<0x80)||(m_data[i]>=0xf0)) m_loopHelper++;
+      }
+   } else if(m_encoding==ENCODING_DELTA2) {
+      // initialize loop helper, a trick to optimize the pattern loop
+      // (the loop is optimized by determining the (fixed) number of loops)
+      for(uint32_t i=0;i<m_nData;i++) {
+         if((m_data[i]<0x80)||(m_data[i]>=0xc0)) m_loopHelper++;
+      }
+   } else if(m_encoding==ENCODING_U7) {
+      // initialize loop helper
+      // (the loop is optimized by splitting off a first look which goes
+      //  without if statement)
+      m_loopHelper=m_nData;
+      for(uint32_t i=0;i<m_nData;i++) {
+         if(m_data[i]>0x80) {
+            m_loopHelper=i;
+            break;
+         }
+      }
+   }
+}
+
+void FTK_CompressedPatternList::exportData
+(Int_t *firstPattern,Int_t *nPattern,Int_t *encoding,
+ std::vector<Int_t> &deltaData) const {
+   *firstPattern=m_FirstPattern;
+   *nPattern=m_NPattern;
+   *encoding=m_encoding;
+   deltaData.reserve(m_nData);
+   deltaData.resize(0);
+   for(size_t i=0;i<m_nData;i++) {
+      deltaData.push_back(m_data[i]);
+   }
+}
+
+uint32_t FTK_CompressedPatternList::selectEncoding(uint32_t defaultMode) const {
+   uint32_t r=defaultMode;
+   if((r<ENCODING_MIN)||(r>ENCODING_MAX)) {
+      r=m_encoding;
+      // analyze delta data
+      // quick analysis of multiplicity data
+      if(m_encoding==ENCODING_DELTA) {
+         int n[4];
+         int nLong=0;
+         n[0]=1;
+         for(size_t i=1;i<4;i++) n[i]=0;
+         for(uint32_t i=0;i<m_nData;i++) {
+            uint8_t d=m_data[i];
+            if(d<0x80) n[0]++;
+            else if(d>=0xf0) {
+               d-=0xee;
+               if(d>3) {
+                  nLong+=d;
+               }
+               while(d>3) {
+                  d-=4;
+                  n[3]++;
+               }
+               if(d) n[d-1]++;
+            }
+         }
+         uint32_t sum=n[0]+n[1]+n[2]+n[3];
+         double multiplicity=(n[0]+2*n[1]+3*n[2]+4*n[3])/(double)sum;
+         if(multiplicity>=2) {
+            // BIT4 is expected to be good (?) if multiplicity is very high
+            r=ENCODING_BIT4;
+         } else if(nLong<n[0]) {
+            // U7 is expected to be good if
+            // long sequences are suppressed compared to single patterns
+            r=ENCODING_U7;
+         } else {
+            // DELTA
+            // fair compromize of everyting
+         }
+      }
+   }
+   // few patterns only -> use U7
+   if((getNPattern()<=10)&&(r==ENCODING_BIT4)) {
+      r=ENCODING_U7;
+   }
+   return r;
+}
+
+void FTK_CompressedPatternList::encode
+(uint32_t encoding,uint32_t *firstPattern,std::vector<uint8_t> &data) const {
+   // loop over all patterns
+
+   if(encoding==ENCODING_BIT4) {
+      FTK_CompressedPatternListBIT4Encoder encoder(data);
+      patternLoop(encoder);
+      *firstPattern=encoder.getFirstPattern();
+   } else if(encoding==ENCODING_DELTA2) {
+      FTK_CompressedPatternListDelta2Encoder encoder(data);
+      patternLoop(encoder);
+      *firstPattern=encoder.getFirstPattern();
+   } else if(encoding==ENCODING_U32) {
+      FTK_CompressedPatternListU32Encoder encoder(data);
+      patternLoop(encoder);
+      *firstPattern=encoder.getFirstPattern();
+   } else if(encoding==ENCODING_U7) {
+      FTK_CompressedPatternListU7Encoder encoder(data);
+      patternLoop(encoder);
+      *firstPattern=encoder.getFirstPattern();
+   } else {
+      FTK_CompressedPatternListDeltaEncoder encoder(data);
+      patternLoop(encoder);
+      *firstPattern=encoder.getFirstPattern();
+   }
+}
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedSectorPatternList.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedSectorPatternList.cxx
new file mode 100644
index 000000000000..368ebff3851e
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_CompressedSectorPatternList.cxx
@@ -0,0 +1,217 @@
+#include "TrigFTKSim/FTK_CompressedSectorPatternList.h"
+#include <iostream>
+#include <iomanip>
+
+// #define COMPRESSION_CHECK
+
+FTK_CompressedSectorPatternList::FTK_CompressedSectorPatternList(void) {
+   m_tempBuffer=0;
+   m_compressedData=0;
+   m_total=0;
+}
+
+FTK_CompressedSectorPatternList::~FTK_CompressedSectorPatternList() {
+   if(m_tempBuffer) delete m_tempBuffer;
+   if(m_compressedData) delete [] m_compressedData;
+}
+
+uint32_t FTK_CompressedSectorPatternList::getNPattern(void) const {
+   uint32_t r=0;
+   for(const_iterator iSector=begin();iSector!=end();iSector++) {
+      r += (*iSector).second.getNPattern();
+   }
+   return r;
+}
+
+uint32_t FTK_CompressedSectorPatternList::getMemoryEstimate(void) const {
+   uint32_t r=sizeof(*this)+sizeof(uint8_t)*m_total+
+      size()*sizeof(FTK_CompressedPatternList);
+   if(m_tempBuffer) {
+      for(std::map<uint32_t,std::vector<uint8_t> >::const_iterator i=
+             m_tempBuffer->begin();i!=m_tempBuffer->end();i++) {
+         r += (*i).second.size();
+      }
+   }
+   return r;
+}
+
+void FTK_CompressedSectorPatternList::importData
+(uint32_t sector,uint32_t firstPattern,uint32_t nPattern,uint32_t encoding,
+ uint32_t nData,Int_t const *intData) {
+   if(!m_tempBuffer) {
+      m_tempBuffer=new std::map<uint32_t,std::vector<uint8_t> >;
+   }
+   std::vector<uint8_t> &data8((*m_tempBuffer)[sector]);
+   data8.reserve(nData);
+   for(size_t i=0;i<nData;i++) {
+      data8.push_back(intData[i]);
+   }
+   insert(std::make_pair(sector,FTK_CompressedPatternList
+                         (firstPattern,nPattern,nData,encoding,data8.data())));
+}
+
+void FTK_CompressedSectorPatternList::importPatternSet
+(uint32_t sector,std::set<uint32_t> const &patterns,int encoding) {
+   if(!m_tempBuffer) {
+      m_tempBuffer=new std::map<uint32_t,std::vector<uint8_t> >;
+   }
+   if((encoding<FTK_CompressedPatternList::ENCODING_MIN)||
+      (encoding>=FTK_CompressedPatternList::ENCODING_MAX)) {
+      encoding=FTK_CompressedPatternList::ENCODING_DELTA;
+   }
+   uint32_t nPattern=patterns.size();
+   std::vector<uint8_t> &data((*m_tempBuffer)[sector]);
+   data.reserve(4*nPattern);
+   FTK_CompressedPatternListEncoder_base *encoder=0;
+   if(encoding==FTK_CompressedPatternList::ENCODING_BIT4) {
+      encoder=new FTK_CompressedPatternListBIT4Encoder(data);
+   } else if(encoding==FTK_CompressedPatternList::ENCODING_DELTA2) {
+      encoder=new FTK_CompressedPatternListDelta2Encoder(data);
+   } else if(encoding==FTK_CompressedPatternList::ENCODING_U32) {
+      encoder=new FTK_CompressedPatternListU32Encoder(data);
+   } else if(encoding==FTK_CompressedPatternList::ENCODING_U7) {
+      encoder=new FTK_CompressedPatternListU7Encoder(data);
+   } else {
+      encoder=new FTK_CompressedPatternListDeltaEncoder(data);
+   }
+   std::set<uint32_t>::const_iterator i=patterns.begin(),i0;
+   encoder->init(*i);
+   encoder->process();
+   for(i0=i++;i!=patterns.end();i0=i++) {
+      encoder->update((*i)-(*i0));
+      encoder->process();
+   }
+   data.shrink_to_fit();
+   insert(std::make_pair(sector,FTK_CompressedPatternList
+                         (encoder->getFirstPattern(),nPattern,data.size(),
+                          encoding,data.data()))); 
+   delete encoder;
+}
+
+
+void FTK_CompressedSectorPatternList::finalize(int compressionMode) {
+   if(m_tempBuffer) {
+      if(m_compressedData) {
+         // should never happen
+         std::cout<<"FTK_CompressedSectorPatternList packed and non-packed data"
+            " are mixed\n";
+         exit(12);
+      }
+      // enforce a specific compression scheme
+      uint32_t maxSize=0;
+      for(iterator plist=begin();plist!=end();plist++) {
+         if((*plist).second.getEncoding()!=(uint32_t)compressionMode) {
+            if((*plist).second.getNPattern()>maxSize) {
+               maxSize=(*plist).second.getNPattern();
+            }
+         }
+      }
+      std::vector<uint8_t> tmpData;
+      tmpData.reserve(maxSize);
+#ifdef COMPRESSION_CHECK
+      std::vector<uint8_t> test1;
+      std::vector<uint8_t> test2;
+      std::vector<uint8_t> orig;
+      test1.reserve(maxSize);
+      test2.reserve(maxSize);
+      orig.reserve(maxSize);
+#endif
+      for(iterator plist=begin();plist!=end();plist++) {
+         uint32_t compressionType=(*plist).second.selectEncoding
+            (compressionMode);
+         if((*plist).second.getEncoding()!=(uint32_t)compressionType) {
+            uint32_t firstPattern;
+#ifdef COMPRESSION_CHECK
+            uint32_t first1,first2;
+            (*plist).second.encode(FTK_CompressedPatternList::ENCODING_U32,
+                                   &first1,test1);
+#endif
+            (*plist).second.encode(compressionType,&firstPattern,tmpData);
+            std::map<uint32_t,std::vector<uint8_t> >::iterator iBuffer=
+               m_tempBuffer->find((*plist).first);
+            if(iBuffer!=m_tempBuffer->end()) {
+               size_t n=tmpData.size();
+#ifdef COMPRESSION_CHECK
+               orig.swap((*iBuffer).second);
+#endif
+               (*iBuffer).second.reserve(n);
+               (*iBuffer).second.resize(n);
+               if((*iBuffer).second.size()) {
+                  memcpy((*iBuffer).second.data(),tmpData.data(),n);
+               }
+               (*plist).second.setData
+                  (firstPattern,compressionType,(*iBuffer).second);
+            }
+#ifdef COMPRESSION_CHECK
+            (*plist).second.encode(FTK_CompressedPatternList::ENCODING_U32,
+                                   &first2,test2);
+            uint32_t error=0;
+            if(test1.size()!=test2.size()) {
+               error++;
+            }
+            if(first1!=first2) {
+               error++;
+            }
+            for(size_t k=0;(k<test1.size())&&(k<test2.size());k++) {
+               if(test1[k]!=test2[k]) error++;
+            }
+            if(error) {
+               std::cout<<"first: "<<first1<<" "<<first2<<"\n";
+               std::cout<<"size: "<<test1.size()<<" "<<test2.size()<<"\n";
+               for(size_t k=0;(k<test1.size())||(k<test2.size());k+=4) {
+                  std::cout<<" "<<k;
+                  uint32_t x1=0,x2=0;
+                  int s=0;
+                  for(size_t l=0;l<3;l++) {
+                     if(k+l<test1.size()) x1 |= ((uint32_t)test1[k+l])<<s;
+                     if(k+l<test2.size()) x2 |= ((uint32_t)test2[k+l])<<s;
+                     s+=8;
+                  }
+                  std::cout<<" "<<x1<<" "<<x2
+                           <<std::setbase(16)<<" 0x"<<x1<<" 0x"<<x2
+                           <<std::setbase(10)<<"\n";
+               }
+               std::cout<<"original encoded data\n";
+               for(size_t k=0;k<orig.size();k++) {
+                  std::cout<<std::setbase(16)<<" 0x"<<(int)orig[k];
+               }
+               std::cout<<"\n";
+               std::cout<<"newly encoded data\n";
+               for(size_t k=0;k<tmpData.size();k++) {
+                  std::cout<<std::setbase(16)<<" 0x"<<(int)tmpData[k];
+               }
+               std::cout<<"\n";
+               exit(111);
+            }
+#endif
+         }
+      }
+
+      // calculate total size
+      size_t total=0;
+      for(std::map<uint32_t,std::vector<uint8_t> >::const_iterator
+             iSector=m_tempBuffer->begin();iSector!=m_tempBuffer->end();
+          iSector++) {
+         total += (*iSector).second.size();
+      }
+      // reserve continuous memory block
+      m_compressedData=new uint8_t[total];
+      m_total=total;
+      uint8_t *ptr=m_compressedData;
+      // copy data to continuous memory block
+      for(std::map<uint32_t,std::vector<uint8_t> >::const_iterator
+             iSector=m_tempBuffer->begin();iSector!=m_tempBuffer->end();
+          iSector++) {
+         if((*iSector).second.size()==0) continue;
+         iterator plistPtr=find((*iSector).first);
+         if(plistPtr!=end()) {
+            (*plistPtr).second.setDataPointer(ptr);
+            memcpy(ptr,(*iSector).second.data(),(*iSector).second.size());
+            ptr += (*iSector).second.size();
+         }
+      }
+      // delete temporary space
+      delete m_tempBuffer;
+      m_tempBuffer=0;
+   }
+}
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_HitMask.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_HitMask.cxx
new file mode 100644
index 000000000000..b340627e06f2
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_HitMask.cxx
@@ -0,0 +1,45 @@
+#include "TrigFTKSim/FTK_HitMask.h"
+
+#ifdef USE_32BIT_CONTAINER
+
+void FTK_HitMaskVector::init(uint32_t first,uint32_t last,FTK_HitMask data) {
+   uint32_t w0=first>>2;
+   uint32_t w1=w0+1;
+   uint32_t w2=last>>2;
+   uint8_t firstWordFirstBit=first &3;
+   uint8_t lastWordLastBit=last &3;
+   uint8_t firstWordLastBit=3;
+   if(w0==w2) {
+      // first word=last word
+      firstWordLastBit=lastWordLastBit;
+   }
+   // construct mask and data for bit number zero 
+   FTK_HitMask4 mask1=0x11111111;
+   FTK_HitMask4 data1=0;
+   for(uint8_t bit=0;bit<8;bit++) {
+      if(data & (1<<bit)) data1 |= 1<<(bit<<2);
+   }
+   // construct mask and data for first word
+   int bitsFirstWord = (1<<(firstWordLastBit+1))
+      -(1<<firstWordFirstBit);
+   // example:
+   //  firstWordFirstBit=1
+   //  firstWordLastBit=3
+   // -> bitsFirstWord = (1<<4)-(1<<2) = 0x0e  -> binary 1110
+   //   (bits 1,2,3 are set, i.e. in the range [1,3])
+
+   // clear bits which are not in mask1, set bits in data1
+   m_data4[w0] = (m_data4[w0]& ~(mask1*bitsFirstWord))|(data1*bitsFirstWord);
+
+   if(w0!=w2) {
+      // construct mask for last word
+      int bitsLastWord = (1<<(lastWordLastBit+1))-(1<<0);
+      m_data4[w2] = (m_data4[w2]& ~(mask1*bitsLastWord))|(data1*bitsLastWord);
+
+      // handle bulk of data -> all bits used
+      FTK_HitMask4 dataF=data1*0xf;
+      for(uint32_t w=w1;w<w2;w++) m_data4[w]=dataF;
+   }
+}
+
+#endif
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_RawInput.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_RawInput.cxx
index 8124777d6a5e..1fb5e1ba9a45 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTK_RawInput.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_RawInput.cxx
@@ -7,7 +7,7 @@
 #include "TrigFTKSim/FTKSetup.h"
 #include "TrigFTKSim/FTKRoadFileInput.h"
 #include "TrigFTKSim/FTK_RawInput.h"
-#include "TrigFTKSim/atlClustering.h"
+#include "TrigFTKSim/FTKClusteringEngine.h"
 #include "TrigFTKSim/MultiTruth.h"
 #include "TrigFTKSim/PatternBank.h"
 
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_RegionalRawInput.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_RegionalRawInput.cxx
index 36fd63e0883d..16148a36913a 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTK_RegionalRawInput.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_RegionalRawInput.cxx
@@ -7,7 +7,6 @@
 #include "TrigFTKSim/FTKSetup.h"
 #include "TrigFTKSim/FTKRoadFileInput.h"
 #include "TrigFTKSim/FTK_RegionalRawInput.h"
-#include "TrigFTKSim/atlClustering.h"
 #include "TrigFTKSim/MultiTruth.h"
 #include "TrigFTKSim/PatternBank.h"
 
@@ -32,7 +31,7 @@ using namespace std;
 FTK_RegionalRawInput::FTK_RegionalRawInput(const FTKPlaneMap *pmap, const FTKPlaneMap *pmap_unused,bool readTruthTracks) :
   FTKDataInput(pmap,pmap_unused),
   m_curfile(0x0),
-  m_hittree(0), m_hittree_branch(0), m_evtnum(0), m_evtnumE(0), m_evtinfo(0), m_trackstree(0), 
+  m_hittree(0), m_hittree_branch(0), m_evtnum(0), m_evtnumE(0), m_evtinfo(0), m_trackstree(0),
   m_glob_event(0), m_ntruth_tracks(0),m_readTruthTracks(readTruthTracks),m_truthTracksTree(0)
 {
   m_regional = true;
@@ -40,17 +39,17 @@ FTK_RegionalRawInput::FTK_RegionalRawInput(const FTKPlaneMap *pmap, const FTKPla
 
 FTK_RegionalRawInput::FTK_RegionalRawInput(const FTK_RegionalRawInput& v) :
   FTKDataInput(v),
-  m_curfile(v.m_curfile), 
-  m_hittree(0), m_hittree_branch(0), m_evtnum(0), m_evtnumE(0), m_evtinfo(0), m_trackstree(0), 
+  m_curfile(v.m_curfile),
+  m_hittree(0), m_hittree_branch(0), m_evtnum(0), m_evtnumE(0), m_evtinfo(0), m_trackstree(0),
   m_glob_event(v.m_glob_event), m_ntruth_tracks(0),m_readTruthTracks(v.m_readTruthTracks),m_truthTracksTree(0)
-{ 
+{
   m_regional = true;
 }
 
 FTK_RegionalRawInput::~FTK_RegionalRawInput()
 {
   if(m_trackinput) {
-    for(int i=0;i<m_nregions;i++) 
+    for(int i=0;i<m_nregions;i++)
       {
 	if (i!=m_region) continue;
 	delete m_trackinput[i];
@@ -58,7 +57,7 @@ FTK_RegionalRawInput::~FTK_RegionalRawInput()
     delete[] m_trackinput;
   }
   if(m_roadinput) {
-    for(int i=0;i<m_nregions;i++) 
+    for(int i=0;i<m_nregions;i++)
       {
 	if (i!=m_region) continue;
 	delete m_roadinput[i];
@@ -95,7 +94,7 @@ int FTK_RegionalRawInput::addFilesList(const char *listpath)
       // comment, skip tis line
       continue;
     }
-    else if (line.size()==0) { 
+    else if (line.size()==0) {
       // empty line, skip
       continue;
     }
@@ -124,7 +123,7 @@ int FTK_RegionalRawInput::addTrackFile(int bank, const char *path) {
 */
 int FTK_RegionalRawInput::addTrackFilesList(int bank, const char *listpath) {
   cout << "in addFilesList_trk" << endl;
-  if(!m_trackinput || !m_trackinput[bank]) 
+  if(!m_trackinput || !m_trackinput[bank])
     {
       return -1;
     }
@@ -146,7 +145,7 @@ int FTK_RegionalRawInput::addRoadFile(int bank, const char *path) {
   int res = access(path,R_OK);
   if(res) return -1;
   if(!m_roadinput || !m_roadinput[bank]) return -1;
-  return m_roadinput[bank]->addFile(path);  
+  return m_roadinput[bank]->addFile(path);
 }
 
 /**
@@ -154,7 +153,7 @@ int FTK_RegionalRawInput::addRoadFile(int bank, const char *path) {
 */
 int FTK_RegionalRawInput::addRoadFilesList(int bank, const char *listpath) {
   cout << "in addFilesList_rd" << endl;
-  if(!m_roadinput || !m_roadinput[bank]) 
+  if(!m_roadinput || !m_roadinput[bank])
     {
       return -1;
     }
@@ -170,13 +169,13 @@ const char* FTK_RegionalRawInput::getCurrentRoadFileName(int bank) {
 }
 
 
-/** this method move to the next file in the list and 
+/** this method move to the next file in the list and
     reset the related flag */
 int FTK_RegionalRawInput::nextFile()
 {
    if (m_read_FTKhits_directly) FTKSetup::PrintMessageFmt(ftk::info,"Reading hits in directly as FTKHits, skipping FTKRawHits.\n");
 
-   if (!m_init) { 
+   if (!m_init) {
     m_current_path = m_files_path.begin();
     m_init = true;
    }
@@ -239,7 +238,7 @@ int FTK_RegionalRawInput::nextFile()
        return 0;
     }
   }
-  
+
   FTKSetup::PrintMessage(ftk::warn,"End of files list reached\n");
   return -1;
 }
@@ -247,7 +246,7 @@ int FTK_RegionalRawInput::nextFile()
 /** initilize the input */
 int FTK_RegionalRawInput::init(bool *goodRegions)
 {
-  // setup clustering 
+  // setup clustering
   initClustering();
 
   // set the region to read and the ones to be skipped
@@ -255,7 +254,7 @@ int FTK_RegionalRawInput::init(bool *goodRegions)
   for (int ireg=0;ireg!=m_nregions;++ireg) {
     m_goodRegions[ireg] = goodRegions[ireg];
   }
-  
+
   // prepare the objects read the file
   m_hittree_branch = new TBranch*[m_nregions];
   m_original_reghits = new vector<FTKRawHit>*[m_nregions];
@@ -322,7 +321,7 @@ int FTK_RegionalRawInput::readData() {
   int res(0);
 
   do {
-     if (m_evtnum==m_evtnumE) { 
+     if (m_evtnum==m_evtnumE) {
         // reached last event go to the next file
         if (nextFile()==-1) {
            // read failed, attempt to use the next file
@@ -330,7 +329,7 @@ int FTK_RegionalRawInput::readData() {
         }
         res = 1;
      }
-     
+
      for (int ireg=0;ireg!=m_nregions;++ireg) {
         if (!m_goodRegions[ireg]) continue;
         // read the hits related to this tower
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/FTK_SGTrackOutput.cxx b/Trigger/TrigFTK/TrigFTKSim/src/FTK_SGTrackOutput.cxx
index 7fa12970eb52..aba91f56295a 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/FTK_SGTrackOutput.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/FTK_SGTrackOutput.cxx
@@ -11,9 +11,10 @@ using namespace std;
 FTK_SGTrackOutput::FTK_SGTrackOutput(const std::string& algname, const std::string &name, const IInterface *ifc) :
   AthAlgTool(algname,name,ifc),
   m_nbanks(0),
-  m_tracks(0x0), m_TFstats(0x0),
+  m_tracks(0x0), m_tracks_pre_hw(0x0), m_TFstats(0x0),
   m_storeIncomplete(false),
-  m_tracksI(0x0), m_TFstatsI(0x0),
+  m_tracksI(0x0), m_tracksI_pre_hw(0x0), m_TFstatsI(0x0),
+  m_tracks_pattern(0x0), m_tracks_hits(0x0),
   m_log( msgSvc() , name )
 {
   declareInterface<FTK_SGTrackOutputI>(this);
@@ -50,9 +51,13 @@ StatusCode FTK_SGTrackOutput::finalize()
   m_log << MSG::INFO << "FTK_SGTrackOutput::finalize()" << endmsg;
 
   if (m_tracks) delete [] m_tracks;
+  if (m_tracks_pre_hw) delete [] m_tracks_pre_hw;
   if (m_TFstats) delete [] m_TFstats;
   if (m_tracksI) delete [] m_tracksI;
+  if (m_tracksI_pre_hw) delete [] m_tracksI_pre_hw;
   if (m_TFstatsI) delete [] m_TFstatsI;
+  if (m_tracks_pattern) delete [] m_tracks_pattern;
+  if (m_tracks_hits) delete [] m_tracks_hits;
 
   return StatusCode::SUCCESS;
 }
@@ -64,12 +69,20 @@ void FTK_SGTrackOutput::init(int, bool*)
 {
   // create the array of track arrays
   m_tracks = new FTKAthTrackContainer*[m_nbanks];
+  // create the array of track arrays before Hit Warrior
+  m_tracks_pre_hw = new FTKAthTrackContainer*[m_nbanks];
   // create an array of TF stats
   m_TFstats = new FTKTrackFitterStats*[m_nbanks];
   // create the array of track arrays
   m_tracksI = new FTKAthTrackContainer*[m_nbanks];
+  // create the array of track arrays before Hit Warrior
+  m_tracksI_pre_hw = new FTKAthTrackContainer*[m_nbanks];
   // create an array of TF stats
   m_TFstatsI = new FTKTrackFitterStats*[m_nbanks];
+  // create the array of track arrays with pattern
+  m_tracks_pattern = new FTKAthTrackContainer*[m_nbanks];
+  // create the array of track arrays that pass the hits requirements
+  m_tracks_hits = new FTKAthTrackContainer*[m_nbanks];
 }
 
 
@@ -83,9 +96,13 @@ void FTK_SGTrackOutput::eventBegin()
      should be freed by the SG  */
   for (int ib=0;ib!=m_nbanks;++ib) {
     m_tracks[ib] = new FTKAthTrackContainer();
+    m_tracks_pre_hw[ib] = new FTKAthTrackContainer();
     m_TFstats[ib] = new FTKTrackFitterStats();
     m_tracksI[ib] = new FTKAthTrackContainer();
+    m_tracksI_pre_hw[ib] = new FTKAthTrackContainer();
     m_TFstatsI[ib] = new FTKTrackFitterStats();
+    m_tracks_pattern[ib] = new FTKAthTrackContainer();
+    m_tracks_hits[ib] = new FTKAthTrackContainer();
   }
 }
 
@@ -108,6 +125,19 @@ void FTK_SGTrackOutput::eventEnd()
       m_log << MSG::DEBUG << "Wrote FTK track container data class " << endmsg;
     }
 
+    ostringstream track_pre_hw_contname;
+    track_pre_hw_contname << "FTKTracks_pre_hw" << ibank << ends;
+    sc = m_storeGate->record(m_tracks_pre_hw[ibank],track_pre_hw_contname.str().c_str());
+    if ( sc.isFailure() ) {
+      m_log << MSG::ERROR
+      << "Could not register FTK track container data"
+      << endmsg;
+      return;
+    }
+    else {
+      m_log << MSG::DEBUG << "Wrote FTK track container data class " << endmsg;
+    }
+
     ostringstream info_contname;
     info_contname << "FTKTFSummary" << ibank << ends;
     sc = m_storeGate->record(m_TFstats[ibank],info_contname.str().c_str());
@@ -138,6 +168,19 @@ void FTK_SGTrackOutput::eventEnd()
       m_log << MSG::DEBUG << "Wrote FTK track container data class " << endmsg;
     }
 
+    ostringstream trackI_pre_hw_contname;
+    trackI_pre_hw_contname << "FTKTracksI_pre_hw" << ibank << ends;
+    sc = m_storeGate->record(m_tracksI_pre_hw[ibank],trackI_pre_hw_contname.str().c_str());
+    if ( sc.isFailure() ) {
+      m_log << MSG::ERROR
+      << "Could not register FTK track container data"
+      << endmsg;
+      return;
+    }
+    else {
+      m_log << MSG::DEBUG << "Wrote FTK track container data class " << endmsg;
+    }
+
     ostringstream infoI_contname;
     infoI_contname << "FTKTFSummaryI" << ibank << ends;
     sc = m_storeGate->record(m_TFstatsI[ibank],infoI_contname.str().c_str());
@@ -151,6 +194,32 @@ void FTK_SGTrackOutput::eventEnd()
       m_log << MSG::DEBUG << "Wrote FTK track fitter data class " << endmsg;
     }
 
+    ostringstream track_pattern_contname;
+    track_pattern_contname << "FTKTracks_pattern" << ibank << ends;
+    sc = m_storeGate->record(m_tracks_pattern[ibank],track_pattern_contname.str().c_str());
+    if ( sc.isFailure() ) {
+      m_log << MSG::ERROR
+      << "Could not register FTK track container data"
+      << endmsg;
+      return;
+    }
+    else {
+      m_log << MSG::DEBUG << "Wrote FTK track container data class " << endmsg;
+    }
+
+    ostringstream track_hits_contname;
+    track_hits_contname << "FTKTracks_hits" << ibank << ends;
+    sc = m_storeGate->record(m_tracks_hits[ibank],track_hits_contname.str().c_str());
+    if ( sc.isFailure() ) {
+      m_log << MSG::ERROR
+      << "Could not register FTK track container data"
+      << endmsg;
+      return;
+    }
+    else {
+      m_log << MSG::DEBUG << "Wrote FTK track container data class " << endmsg;
+    }
+
   } // end bank loop
 }
 
@@ -206,6 +275,48 @@ void FTK_SGTrackOutput::addTrack(int bank, const FTKTrack &track)
   m_tracks[bank]->push_back(athtrack);
 }
 
+/** The method converts the original FTKTrack in a FTKAthTrack
+    and add the latter in the list */
+void FTK_SGTrackOutput::addTrack_pre_hw(int bank, const FTKTrack &track)
+{
+  //track.Print();
+
+  // create the track
+  FTKAthTrack *athtrack = new FTKAthTrack(track.getNCoords());
+  // copy the FTKTrack content into the FTKAthTrack class
+  // copy the IDs that identify the algorithm flow
+  athtrack->setBankID(track.getBankID());
+  athtrack->setRoadID(track.getRoadID());
+  athtrack->setPatternID(track.getPatternID());
+  athtrack->setSectorID(track.getSectorID());
+  athtrack->setTrackID(track.getTrackID());
+  // copy the helix parameters
+  athtrack->setHalfInvPt(track.getHalfInvPt());
+  athtrack->setIP(track.getIP());
+  athtrack->setPhi(track.getPhi());
+  athtrack->setZ0(track.getZ0());
+  athtrack->setCotTheta(track.getCotTheta());
+  athtrack->setChi2(track.getChi2());
+  athtrack->setOrigChi2(track.getOrigChi2());
+  // copy the coordinates
+  for (int ix=0;ix!=track.getNCoords();++ix)
+    athtrack->setCoord(ix,track.getCoord(ix));
+  // copy the quality fields
+  athtrack->setNMissing(track.getNMissing());
+  athtrack->setTypeMask(track.getTypeMask());
+  athtrack->setBitmask(track.getBitmask());
+  athtrack->setHFRejected(track.getHFRejected());
+  athtrack->setHWRejected(track.getHWRejected());
+  athtrack->setHWTrackID(track.getHWTrackID());
+  // copy the G4 truth matching fields
+  athtrack->setEventIndex(track.getEventIndex());
+  athtrack->setBarcode(track.getBarcode());
+  athtrack->setBarcodeFrac(track.getBarcodeFrac());
+
+  // FTKAthTrackContainer is defined to own the pointers
+  m_tracks_pre_hw[bank]->push_back(athtrack);
+}
+
 void FTK_SGTrackOutput::addNCombs(int ib, int v)
 {
   m_TFstats[ib]->addNCombs(v);
@@ -320,6 +431,126 @@ void FTK_SGTrackOutput::addTrackI(int bank, const FTKTrack &track)
   m_tracksI[bank]->push_back(athtrack);
 }
 
+void FTK_SGTrackOutput::addTrackI_pre_hw(int bank, const FTKTrack &track)
+{
+  //track.Print();
+
+  // create the track
+  FTKAthTrack *athtrack = new FTKAthTrack(track.getNCoords());
+  // copy the FTKTrack content into the FTKAthTrack class
+  // copy the IDs that identify the algorithm flow
+  athtrack->setBankID(track.getBankID());
+  athtrack->setRoadID(track.getRoadID());
+  athtrack->setPatternID(track.getPatternID());
+  athtrack->setSectorID(track.getSectorID());
+  athtrack->setTrackID(track.getTrackID());
+  // copy the helix parameters
+  athtrack->setHalfInvPt(track.getHalfInvPt());
+  athtrack->setIP(track.getIP());
+  athtrack->setPhi(track.getPhi());
+  athtrack->setZ0(track.getZ0());
+  athtrack->setCotTheta(track.getCotTheta());
+  athtrack->setChi2(track.getChi2());
+  athtrack->setOrigChi2(track.getOrigChi2());
+  // copy the coordinates
+  for (int ix=0;ix!=track.getNCoords();++ix)
+    athtrack->setCoord(ix,track.getCoord(ix));
+  // copy the quality fields
+  athtrack->setNMissing(track.getNMissing());
+  athtrack->setTypeMask(track.getTypeMask());
+  athtrack->setBitmask(track.getBitmask());
+  athtrack->setHFRejected(track.getHFRejected());
+  athtrack->setHWRejected(track.getHWRejected());
+  athtrack->setHWTrackID(track.getHWTrackID());
+  // copy the G4 truth matching fields
+  athtrack->setEventIndex(track.getEventIndex());
+  athtrack->setBarcode(track.getBarcode());
+  athtrack->setBarcodeFrac(track.getBarcodeFrac());
+
+  // FTKAthTrackContainer is defined to own the pointers
+  m_tracksI_pre_hw[bank]->push_back(athtrack);
+}
+
+void FTK_SGTrackOutput::addTrack_pattern(int bank, const FTKTrack &track)
+{
+  //track.Print();
+
+  // create the track
+  FTKAthTrack *athtrack = new FTKAthTrack(track.getNCoords());
+  // copy the FTKTrack content into the FTKAthTrack class
+  // copy the IDs that identify the algorithm flow
+  athtrack->setBankID(track.getBankID());
+  athtrack->setRoadID(track.getRoadID());
+  athtrack->setPatternID(track.getPatternID());
+  athtrack->setSectorID(track.getSectorID());
+  athtrack->setTrackID(track.getTrackID());
+  // copy the helix parameters
+  athtrack->setHalfInvPt(track.getHalfInvPt());
+  athtrack->setIP(track.getIP());
+  athtrack->setPhi(track.getPhi());
+  athtrack->setZ0(track.getZ0());
+  athtrack->setCotTheta(track.getCotTheta());
+  athtrack->setChi2(track.getChi2());
+  athtrack->setOrigChi2(track.getOrigChi2());
+  // copy the coordinates
+  for (int ix=0;ix!=track.getNCoords();++ix)
+    athtrack->setCoord(ix,track.getCoord(ix));
+  // copy the quality fields
+  athtrack->setNMissing(track.getNMissing());
+  athtrack->setTypeMask(track.getTypeMask());
+  athtrack->setBitmask(track.getBitmask());
+  athtrack->setHFRejected(track.getHFRejected());
+  athtrack->setHWRejected(track.getHWRejected());
+  athtrack->setHWTrackID(track.getHWTrackID());
+  // copy the G4 truth matching fields
+  athtrack->setEventIndex(track.getEventIndex());
+  athtrack->setBarcode(track.getBarcode());
+  athtrack->setBarcodeFrac(track.getBarcodeFrac());
+
+  // FTKAthTrackContainer is defined to own the pointers
+  m_tracks_pattern[bank]->push_back(athtrack);
+}
+
+void FTK_SGTrackOutput::addTrack_hits(int bank, const FTKTrack &track)
+{
+  //track.Print();
+
+  // create the track
+  FTKAthTrack *athtrack = new FTKAthTrack(track.getNCoords());
+  // copy the FTKTrack content into the FTKAthTrack class
+  // copy the IDs that identify the algorithm flow
+  athtrack->setBankID(track.getBankID());
+  athtrack->setRoadID(track.getRoadID());
+  athtrack->setPatternID(track.getPatternID());
+  athtrack->setSectorID(track.getSectorID());
+  athtrack->setTrackID(track.getTrackID());
+  // copy the helix parameters
+  athtrack->setHalfInvPt(track.getHalfInvPt());
+  athtrack->setIP(track.getIP());
+  athtrack->setPhi(track.getPhi());
+  athtrack->setZ0(track.getZ0());
+  athtrack->setCotTheta(track.getCotTheta());
+  athtrack->setChi2(track.getChi2());
+  athtrack->setOrigChi2(track.getOrigChi2());
+  // copy the coordinates
+  for (int ix=0;ix!=track.getNCoords();++ix)
+    athtrack->setCoord(ix,track.getCoord(ix));
+  // copy the quality fields
+  athtrack->setNMissing(track.getNMissing());
+  athtrack->setTypeMask(track.getTypeMask());
+  athtrack->setBitmask(track.getBitmask());
+  athtrack->setHFRejected(track.getHFRejected());
+  athtrack->setHWRejected(track.getHWRejected());
+  athtrack->setHWTrackID(track.getHWTrackID());
+  // copy the G4 truth matching fields
+  athtrack->setEventIndex(track.getEventIndex());
+  athtrack->setBarcode(track.getBarcode());
+  athtrack->setBarcodeFrac(track.getBarcodeFrac());
+
+  // FTKAthTrackContainer is defined to own the pointers
+  m_tracks_hits[bank]->push_back(athtrack);
+}
+
 void FTK_SGTrackOutput::addNCombsI(int ib, int v)
 {
   m_TFstatsI[ib]->addNCombs(v);
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/RoadFinder.cxx b/Trigger/TrigFTK/TrigFTKSim/src/RoadFinder.cxx
index acf3015290c9..32147d288fc0 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/RoadFinder.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/RoadFinder.cxx
@@ -275,6 +275,7 @@ int RoadFinder::nextEvent()
      list<FTKRoad>::const_iterator iroad = roadslist.begin();
      int rid(0);
      bool soft_limit(true), hard_limit(true);
+     FTKRoadStream *stream = m_roadoutput->getStream(m_datainput->getCurrentRegion());
      for (;iroad!=roadslist.end();++iroad) {
        // default case: just save the road
        if (!FTKSetup::getFTKSetup().getSCTtrkMode()) {
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter.cxx b/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter.cxx
index 964a8b225688..08aab18890a8 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter.cxx
@@ -18,19 +18,19 @@ using namespace std;
 //#define DEBUG_HITEXTRAPOLATION
 TrackFitter::TrackFitter() :
   m_ncoords(0), m_nplanes(0), m_npars(5),
-  m_Chi2Cut(0), m_Chi2Cut_maj(0), m_Chi2Cut_vetomaj(-1), m_Chi2DofCut(-1),
-  m_HitWarrior(2), m_HitWarrior_first(1), m_HW_ndiff(3), m_HW_dev(0),
+  m_Chi2Cut(0), m_Chi2Cut_maj(0), m_Chi2Cut_vetomaj(-1), m_Chi2DofCutAux(-1), m_Chi2DofCutSSB(-1),
+  m_HitWarrior(2), m_HW_ndiff(3), m_HW_dev(0),
+  m_AuxDoctor(false),
   m_keep_rejected(0), m_fit_removed(0),
   m_max_ncomb(10000), m_max_nhitsperplane(-1), m_max_trkout(2000000), m_norecovery_nhits(-1),
   m_one_per_road(false), m_require_first(true), m_do_majority(1),
-  // m_one_per_road(true), m_require_first(false), m_do_majority(1),
   m_roadinput(0), m_trackoutput(0), m_trackoutput_pre_hw(0),
-  //m_fwoutput(0), m_maxsectors_fwo(0), m_nsectors_fwo(0), // output for firmware tests
   m_nregions(0), m_nsubregions(0),
   m_constant(0),
   m_goodRegion(0),
   m_noconstants_errlevel(ftk::sevr), m_pmap(0),
   m_ntracks(0),
+  m_ntracks_pre_hw(0),
   m_ncombs(0),
   m_nfits(0),
   m_nfits_maj(0),
@@ -50,7 +50,7 @@ TrackFitter::TrackFitter() :
   m_endlist(0),
   m_hitcnt(0),
   m_identify_badhit(false),
-  m_saveIncompleteTracks(false)
+  m_saveStepByStepTracks(false)
 {
   // nothing to do
 #ifdef DEBUG_HITEXTRAPOLATION
@@ -229,7 +229,7 @@ void TrackFitter::init()
   // counter that enumerates current hit in FTKHit array
   m_hitcnt = new int[m_nplanes];
 
-  m_complete_mask = ~(~0u<<m_ncoords);
+  m_complete_mask = ~(~0<<m_ncoords);
   // allocate once the array of recovered tracks
   m_combtrack = new FTKTrack[m_ncoords];
   for (int ic=0;ic!=m_ncoords;++ic) {
@@ -284,70 +284,14 @@ int TrackFitter::nextEvent()
     // m_trackoutput_pre_hw->setEventNumber( ibank , m_roadinput->eventNumber(ibank) );
 
     const FTKRoad *cur_road = m_roadinput->nextRoad(ibank);
-
-    if (m_HitWarrior_first != 2) {
-
-      while (cur_road) {
-        processor(*cur_road);
-        #if 0 // debug just a limited fraction
-              if (m_nfits>=10000000)
-        	break;
-        #endif
-        cur_road = m_roadinput->nextRoad(ibank);
-      }
-    }
-    else {
-
-      vector<int> vSectorID;
-
-      while (cur_road) {
-        if (std::find(vSectorID.begin(), vSectorID.end(), cur_road->getSectorID()) == vSectorID.end()) vSectorID.push_back(cur_road->getSectorID());
-        cur_road = m_roadinput->nextRoad(ibank);
-      }
-
-      for (unsigned int i = 0; i < vSectorID.size(); i++) {
-        cur_road = m_roadinput->firstRoad(ibank);
-
-        while (cur_road) {
-          if (cur_road->getSectorID() == vSectorID[i]) {
-            m_processor_stage = 1;
-            processor(*cur_road);
-          }
-          cur_road = m_roadinput->nextRoad(ibank);
-        }
-
-        cur_road = m_roadinput->firstRoad(ibank);
-
-        while (cur_road) {
-          if (cur_road->getSectorID() == vSectorID[i]) {
-            m_processor_stage = 2;
-            processor(*cur_road);
-          }
-          cur_road = m_roadinput->nextRoad(ibank);
-        }
-
-        m_tracks_first.splice(m_tracks_first.end(), m_sector_tracks);
-
-      }
-
-      vSectorID.clear();
-      m_sector_tracks.clear();
-
-    }
-
-    if (m_saveIncompleteTracks) {
-      for (list<FTKTrack>::iterator it = m_tracks_first.begin(); it != m_tracks_first.end(); it++) {
-        int region = it->getRegion();
-        m_trackoutput->addTrackI(region,*it);
-      }
-      // itrack = road_tracks_pre_hw.begin();
-      // for (;itrack!=road_tracks_pre_hw.end();++itrack) {
-      //   m_trackoutput_pre_hw->addTrackI(region,*itrack);
-      // }
+    while (cur_road) {
+      processor(*cur_road);
+#if 0 // debug just a limited fraction
+      if (m_nfits>=10000000)
+	break;
+#endif
+      cur_road = m_roadinput->nextRoad(ibank);
     }
-
-    m_tracks_first.clear();
-    
     // now that all roads in the bank are processed, associate geant
     // truth data with the resulting tracks.
 
@@ -373,6 +317,9 @@ void TrackFitter::processor_init(int /*ibank*/)
     m_ntracks = 0;
     m_comb_id = 0;
     m_tracks.clear();
+    m_tracks_pre_hw.clear();
+    m_tracks_hits.clear();
+    m_tracks_pattern.clear();
 
     // reset counters
     m_ncombs = 0;
@@ -398,6 +345,24 @@ void TrackFitter::processor_end(int ibank)
   for (;itrack2!=m_tracks.end();itrack2 = m_tracks.erase(itrack2)) {
     m_trackoutput->addTrack(ibank,*itrack2);
   }
+
+  if (m_saveStepByStepTracks) {
+    itrack2 = m_tracks_pre_hw.begin();
+    for (;itrack2!=m_tracks_pre_hw.end();itrack2 = m_tracks_pre_hw.erase(itrack2)) {
+      m_trackoutput->addTrack_pre_hw(ibank,*itrack2);
+    }
+
+    // itrack2 = m_tracks_hits.begin();
+    // for (;itrack2!=m_tracks_hits.end();itrack2 = m_tracks_hits.erase(itrack2)) {
+    //   m_trackoutput->addTrack_hits(ibank,*itrack2);
+    // }
+
+    // itrack2 = m_tracks_pattern.begin();
+    // for (;itrack2!=m_tracks_pattern.end();itrack2 = m_tracks_pattern.erase(itrack2)) {
+    //   m_trackoutput->addTrack_pattern(ibank,*itrack2);
+    // }
+  }
+
   // itrack2 = m_tracks_pre_hw.begin();
   // for (;itrack2!=m_tracks_pre_hw.end();itrack2 = m_tracks.erase(itrack2)) {
   //   m_trackoutput_pre_hw->addTrack(ibank,*itrack2);
@@ -462,23 +427,23 @@ void TrackFitter::processor(const FTKRoad &road) {
   FTKConstantBank *current_bank = m_constant[region][subreg];
   if (!current_bank) { // no valid constants
     FTKSetup::PrintMessageFmt(m_noconstants_errlevel,
-			      "*** Constants for region %d - %d don't exists",
-			      region,subreg);
+            "*** Constants for region %d - %d don't exists",
+            region,subreg);
     return;
   }
   // check if the number of sector is compatible with this bank
   else if (sector>=current_bank->getNSectors()) {
     FTKSetup::PrintMessageFmt(m_noconstants_errlevel,
-			      "*** Constants for Sector %d in region %d - %d don't exists\n",
-			      sector,region,subreg);
+            "*** Constants for Sector %d in region %d - %d don't exists\n",
+            sector,region,subreg);
 
     return;
   }
   // check if the sector has a valid constants set
   else if (!current_bank->getIsGood(sector)) {
     FTKSetup::PrintMessageFmt(m_noconstants_errlevel,
-			      "*** Constants for Sector %d in region %d - %d is not valid\n",
-			      sector,region,subreg);
+            "*** Constants for Sector %d in region %d - %d is not valid\n",
+            sector,region,subreg);
 
     return;
   }
@@ -527,17 +492,17 @@ void TrackFitter::processor(const FTKRoad &road) {
        // decide if a 1D or 2D hit
        int ndim = iy==-1 ?  1 : 2;
        if (ndim==1) {
-	 bitmask |= 1 << ix;
-	 nmissing -= 1;
+   bitmask |= 1 << ix;
+   nmissing -= 1;
        }
        else {
-	 bitmask |= ( (1<<ix) | (1<<iy));
-	 nmissing -= 2;
+   bitmask |= ( (1<<ix) | (1<<iy));
+   nmissing -= 2;
        }
        // set the mask to avoid recovery in crowded planes
        // if m_norecovery
        if (m_norecovery_nhits!=-1 && nhits>m_norecovery_nhits)
-	 norecovery_mask |= (1<<p);
+   norecovery_mask |= (1<<p);
      }
    }
 
@@ -577,16 +542,16 @@ void TrackFitter::processor(const FTKRoad &road) {
    for (int comb=0;comb<(ncomb>m_max_ncomb ? m_max_ncomb : ncomb);++comb) {
 
      /* FlagAK:
-	Decide if this hit combination survived hit filter (optional)
-	If hit filter had not been run, this doesn't do anything
+  Decide if this hit combination survived hit filter (optional)
+  If hit filter had not been run, this doesn't do anything
       */
      int hf_nmatches(0);
      for (int ip=0;ip<nplanes;++ip) {
        if(hitcnt[ip]==-1) { // this plane doesn't have any hits
-	 hf_nmatches++;
+   hf_nmatches++;
        }
        else { // this plane has some hits. Test if current hit passed hit filter
-	 if(!road.hit_failed_HF(ip,hitcnt[ip])) hf_nmatches++;
+   if(!road.hit_failed_HF(ip,hitcnt[ip])) hf_nmatches++;
        }
      }
      int hf_rejected = (hf_nmatches != nplanes);
@@ -599,23 +564,23 @@ void TrackFitter::processor(const FTKRoad &road) {
        // this block uses the "m_newtrk" variable that is a field of the object
 
        for (int ip=0;ip<nplanes;++ip) {
-	 // retrieve the coordinate in the final array
-	 int ix = m_pmap->getDim(ip,0);
-	 int iy = m_pmap->getDim(ip,1);
-	 // decide if a 1D or 2D hit
-	 int ndim = iy==-1 ?  1 : 2;
-	 if (position[ip]!=endlist[ip]) {
-	   // set the FTK cluster associated to this layer
-	   m_newtrk.setFTKHit(ip,(*position[ip]));
-
-	   if (ndim==1) {
-	     m_newtrk.setCoord(ix,(*position[ip])[0]);
-	   }
-	   else {
-	     m_newtrk.setCoord(ix,(*position[ip])[0]);
-	     m_newtrk.setCoord(iy,(*position[ip])[1]);
-	   }
-	 }
+   // retrieve the coordinate in the final array
+   int ix = m_pmap->getDim(ip,0);
+   int iy = m_pmap->getDim(ip,1);
+   // decide if a 1D or 2D hit
+   int ndim = iy==-1 ?  1 : 2;
+   if (position[ip]!=endlist[ip]) {
+     // set the FTK cluster associated to this layer
+     m_newtrk.setFTKHit(ip,(*position[ip]));
+
+     if (ndim==1) {
+       m_newtrk.setCoord(ix,(*position[ip])[0]);
+     }
+     else {
+       m_newtrk.setCoord(ix,(*position[ip])[0]);
+       m_newtrk.setCoord(iy,(*position[ip])[1]);
+     }
+   }
        }
        m_newtrk.setTrackID(m_comb_id);
        m_newtrk.setCombinationID(comb);
@@ -627,61 +592,61 @@ void TrackFitter::processor(const FTKRoad &road) {
        // only keep this combination if there are enough hits,
        // otherwise go to next combination.
        if( blayer_condition &&
-	   (!m_one_per_road || (m_one_per_road && nmissing <= min_nmissing) ) ) {
-
-	 if( m_one_per_road && nmissing < min_nmissing ) {
-	   // Don't consider any combinations with more missing hits
-	   min_nmissing = nmissing;
-	   for( std::vector<FTKTrack>::iterator citer = theCombos.begin();
-		citer != theCombos.end(); citer++ ) {
-	     if( (*citer).getNMissing() > min_nmissing ) {
-	       // Presumably this would be handled before this stage
-	       // in the real FTK hardware.
-	       citer = theCombos.erase(citer);
-	       citer--;
-	       m_nfits_maj--;
-	       m_nfits--;
-	       if (missSCT) m_nfits_maj_SCT--;
-	       if (missPix) m_nfits_maj_pix--;
-	     }
-	   }
-	 }
-
-	 // add one fit in the counters
-	 m_nfits++;
-	 if (nmissing>0) {
-	   m_nfits_maj++;
-	   if (missPix) m_nfits_maj_pix++;
-	   if (missSCT) m_nfits_maj_SCT++;
-	 }
-
-
-	 /* Do the actual fit - see code in FTKConstantBank::linfit  */
-	 current_bank->linfit(sector,m_newtrk);
-	 m_newtrk.setOrigChi2(m_newtrk.getChi2());
-
-	 // output for firware tests
-	 //if( dump_fwo ) m_fwoutput->addTrack( m_newtrk );
-
-	 if( m_newtrk.getChi2() != 0 )
-	   theCombos.push_back(m_newtrk);
+     (!m_one_per_road || (m_one_per_road && nmissing <= min_nmissing) ) ) {
+
+   if( m_one_per_road && nmissing < min_nmissing ) {
+     // Don't consider any combinations with more missing hits
+     min_nmissing = nmissing;
+     for( std::vector<FTKTrack>::iterator citer = theCombos.begin();
+    citer != theCombos.end(); citer++ ) {
+       if( (*citer).getNMissing() > min_nmissing ) {
+         // Presumably this would be handled before this stage
+         // in the real FTK hardware.
+         citer = theCombos.erase(citer);
+         citer--;
+         m_nfits_maj--;
+         m_nfits--;
+         if (missSCT) m_nfits_maj_SCT--;
+         if (missPix) m_nfits_maj_pix--;
+       }
+     }
+   }
+
+   // add one fit in the counters
+   m_nfits++;
+   if (nmissing>0) {
+     m_nfits_maj++;
+     if (missPix) m_nfits_maj_pix++;
+     if (missSCT) m_nfits_maj_SCT++;
+   }
+
+
+   /* Do the actual fit - see code in FTKConstantBank::linfit  */
+   current_bank->linfit(sector,m_newtrk);
+   m_newtrk.setOrigChi2(m_newtrk.getChi2());
+
+   // output for firware tests
+   //if( dump_fwo ) m_fwoutput->addTrack( m_newtrk );
+
+   if( m_newtrk.getChi2() != 0 )
+     theCombos.push_back(m_newtrk);
        } // end if nmissing <= min_nmissing
      } // end if !hf_rejected
      /* compose the next combination */
      for (int curpl=0;curpl<nplanes;++curpl) {
        if (startlist[curpl]==endlist[curpl]) // empty hit
-	 continue;
+   continue;
 
        // move to the next
        position[curpl]++;  hitcnt[curpl]++;
        if (position[curpl]!=endlist[curpl] && hitcnt[curpl]!=m_max_nhitsperplane) {
-	 // possible combination
-	 break;
+   // possible combination
+   break;
        }
        else {
-	 // restart on this plane, move the next plane
-	 position[curpl] = startlist[curpl];
-	 hitcnt[curpl] = 0;
+   // restart on this plane, move the next plane
+   position[curpl] = startlist[curpl];
+   hitcnt[curpl] = 0;
        }
      }
 
@@ -701,10 +666,10 @@ void TrackFitter::processor(const FTKRoad &road) {
        int idbestfull(0);
 
        for( unsigned int idx = 1; idx < theCombos.size(); idx++) {
-	 if( theCombos[idx].getChi2() < bestfullchi2 ) {
-	   bestfullchi2 =  theCombos[idx].getChi2();
-	   idbestfull = idx;
-	 }
+   if( theCombos[idx].getChi2() < bestfullchi2 ) {
+     bestfullchi2 =  theCombos[idx].getChi2();
+     idbestfull = idx;
+   }
        }
        m_newtrk = theCombos[idbestfull];
        theCombos.clear();
@@ -728,15 +693,15 @@ void TrackFitter::processor(const FTKRoad &road) {
        float dof = m_ncoords - m_npars - m_newtrk.getNMissing();
        if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
-       if( m_newtrk.getChi2() < ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ) ) {
-	 fullpassed = true;
-	 break;
+       if( m_newtrk.getChi2() < ( m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux : m_Chi2Cut ) ) {
+   fullpassed = true;
+   break;
        }
      }
    }
 
    for( std::vector<FTKTrack>::iterator citer = theCombos.begin();
-	citer != theCombos.end(); citer = theCombos.erase(citer) ) {
+  citer != theCombos.end(); citer = theCombos.erase(citer) ) {
      m_newtrk = *citer;
 
      float dof = m_ncoords - m_npars - m_newtrk.getNMissing();
@@ -757,14 +722,14 @@ void TrackFitter::processor(const FTKRoad &road) {
 #endif
      // Try to recover majority if chi2 no good
      if (m_newtrk.getNMissing()==0 &&
-	 (m_do_majority==1 || (m_do_majority>1 && !fullpassed)) &&
-	 // Do recovery if chi2 or chi2/dof is above threshold
-	 (m_newtrk.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut )) &&
-	 // Or veto majority if chi2 is too high
-	 (m_newtrk.getChi2() < m_Chi2Cut_vetomaj || m_Chi2Cut_vetomaj < 0) ) { // recover majority
+   (m_do_majority==1 || (m_do_majority>1 && !fullpassed)) &&
+   // Do recovery if chi2 or chi2/dof is above threshold
+   (m_newtrk.getChi2() > ( m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux : m_Chi2Cut )) &&
+   // Or veto majority if chi2 is too high
+   (m_newtrk.getChi2() < m_Chi2Cut_vetomaj || m_Chi2Cut_vetomaj < 0) ) { // recover majority
        /* if the N/N track have a bad chi2 we try to evaluate
-	  the track using the "best" track within the N combination
-	  of N-1/N tracks */
+    the track using the "best" track within the N combination
+    of N-1/N tracks */
 
        // in this block the used array of track m_combtrack[] is created
        // in the init block to save some time
@@ -774,43 +739,43 @@ void TrackFitter::processor(const FTKRoad &road) {
        m_nfits_rec += 1;
        for (int ip=(m_require_first?1:0);ip<nplanes;++ip) { // loop over the combinations
 
-	 // skip planes with multiple hits
-	 if (norecovery_mask&(1<<ip)) continue;
+   // skip planes with multiple hits
+   if (norecovery_mask&(1<<ip)) continue;
 
-	 // start for the complete track
-	 m_combtrack[ip] = m_newtrk;
+   // start for the complete track
+   m_combtrack[ip] = m_newtrk;
 
-	 // zero the cluster for the missing layer
-	 m_combtrack[ip].setFTKHit(ip,FTKHit());
+   // zero the cluster for the missing layer
+   m_combtrack[ip].setFTKHit(ip,FTKHit());
 
-	 // remove the hits related with this plane
-	 int ix = m_pmap->getDim(ip,0);
-	 int iy = m_pmap->getDim(ip,1);
-	 int ndim = iy==-1? 1 : 2;
+   // remove the hits related with this plane
+   int ix = m_pmap->getDim(ip,0);
+   int iy = m_pmap->getDim(ip,1);
+   int ndim = iy==-1? 1 : 2;
 
-	 // set the number of missing points and the related bitmask
-	 m_combtrack[ip].setNMissing(m_newtrk.getNMissing()+ndim);
-	 unsigned int newbitmask = (1<<ix);
-	 if (iy!=-1) newbitmask |= (1<<iy);
-	 newbitmask = m_newtrk.getBitmask() & ~newbitmask;
+   // set the number of missing points and the related bitmask
+   m_combtrack[ip].setNMissing(m_newtrk.getNMissing()+ndim);
+   unsigned int newbitmask = (1<<ix);
+   if (iy!=-1) newbitmask |= (1<<iy);
+   newbitmask = m_newtrk.getBitmask() & ~newbitmask;
 
-	 m_combtrack[ip].setBitmask(newbitmask);
+   m_combtrack[ip].setBitmask(newbitmask);
 
-	 // increment the counter of additional fits due to the recovery
-	 m_nfits_addrec += 1;
-	 // attempt the fit
-	 current_bank->linfit(sector,m_combtrack[ip]);
+   // increment the counter of additional fits due to the recovery
+   m_nfits_addrec += 1;
+   // attempt the fit
+   current_bank->linfit(sector,m_combtrack[ip]);
 
-	 // check if the chi2 is better
-	 if (m_combtrack[ip].getChi2()<bestchi2) {
-	   bestchi2 = m_combtrack[ip].getChi2();
-	   idbest = ip;
-	 }
+   // check if the chi2 is better
+   if (m_combtrack[ip].getChi2()<bestchi2) {
+     bestchi2 = m_combtrack[ip].getChi2();
+     idbest = ip;
+   }
        } // end loop over the combinations
 
        if (idbest>=0) {
-	 // a majority track was found
-	 m_newtrk = m_combtrack[idbest];
+   // a majority track was found
+   m_newtrk = m_combtrack[idbest];
 #ifdef DEBUG_HITEXTRAPOLATION
        // Print the best recovery track
        cout << "DBGHIT RC";
@@ -825,9 +790,9 @@ void TrackFitter::processor(const FTKRoad &road) {
      if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
      // check if the track pass the quality requirements
-     if (m_newtrk.getChi2()< ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut :
-			     (m_newtrk.getNMissing() > 0 ? m_Chi2Cut_maj : m_Chi2Cut) )  &&
-	 m_newtrk.getChi2() != 0 ) {
+     if (m_newtrk.getChi2()< ( m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux :
+           (m_newtrk.getNMissing() > 0 ? m_Chi2Cut_maj : m_Chi2Cut) )  &&
+   m_newtrk.getChi2() != 0 ) {
 
        // to append the found track go trought the HW filter
        // add this track to track list only if
@@ -841,47 +806,48 @@ void TrackFitter::processor(const FTKRoad &road) {
 
        // Disable hitwarrior, auto-accept every track
        if (m_HitWarrior!=0)
-	 accepted = doHitWarriorFilter(m_newtrk,m_tracks);
+   accepted = doHitWarriorFilter(m_newtrk,m_tracks);
 
        if (accepted>=0) { // track accepted, no hits shared with already fitted tracks
-	 // match the track to a geant particle using the channel-level
-	 // geant info in the superstrip data.
-	 compute_truth(region,road,m_newtrk);
-	 // copy m_newtrk after truth assignment.
-	 m_tracks.push_back(m_newtrk);
-	 if (accepted==1) {
-	   // this track removed an old one
-	   m_nfits_rej += 1;
-	   if (nmissing>0) m_nfits_rejmaj++;
-	 }
-	 else {
-	   ++m_ntracks;
-	 }
+   // match the track to a geant particle using the channel-level
+   // geant info in the superstrip data.
+   compute_truth(region,road,m_newtrk);
+   // copy m_newtrk after truth assignment.
+   m_tracks.push_back(m_newtrk);
+   if (accepted==1) {
+     // this track removed an old one
+     m_nfits_rej += 1;
+     if (nmissing>0) m_nfits_rejmaj++;
+   }
+   else {
+     ++m_ntracks;
+   }
        }
        else if (accepted==-1) {
-	 // the track is candidate as ghost and is not the best
-	 // clean the list of the hits
-
-	 if (m_keep_rejected) {
-	   // match the track to a geant particle using the channel-level
-	   // geant info in the superstrip data.
-	   compute_truth(region,road,m_newtrk);
-	   // copy m_newtrk after truth assignment.
-	   m_tracks.push_back(m_newtrk);
-	 }
-	 m_nfits_rej += 1;
-	 if (nmissing>0) m_nfits_rejmaj++;
+   // the track is candidate as ghost and is not the best
+   // clean the list of the hits
+
+   if (m_keep_rejected) {
+     // match the track to a geant particle using the channel-level
+     // geant info in the superstrip data.
+     compute_truth(region,road,m_newtrk);
+     // copy m_newtrk after truth assignment.
+     m_tracks.push_back(m_newtrk);
+   }
+
+   m_nfits_rej += 1;
+   if (nmissing>0) m_nfits_rejmaj++;
        }
      }
      else { // if the track fail the cut on chi-square clean the hit list
        if (m_keep_rejected>1) {
-	 m_newtrk.setHWRejected( m_newtrk.getHWRejected()+100 );
+   m_newtrk.setHWRejected( m_newtrk.getHWRejected()+100 );
 
-	 // match the track to a geant particle using the channel-level
-	 // geant info in the superstrip data.
-	 compute_truth(region,road,m_newtrk);
-	 // copy m_newtrk after truth assignment.
-	 m_tracks.push_back(m_newtrk);
+   // match the track to a geant particle using the channel-level
+   // geant info in the superstrip data.
+   compute_truth(region,road,m_newtrk);
+   // copy m_newtrk after truth assignment.
+   m_tracks.push_back(m_newtrk);
        }
        m_nfits_bad += 1;
        if (nmissing>0) m_nfits_badmaj++;
@@ -986,7 +952,7 @@ TrackFitter::compute_truth(const unsigned int& /*ibank*/,const FTKRoad& road,FTK
 
 /** this method attempets to add a track into a list of tracks,
     before to do that applies the usual HW filter */
-int TrackFitter::doHitWarriorFilter(FTKTrack &track_toadd,list<FTKTrack> &tracks_list)
+int TrackFitter::doHitWarriorFilter(FTKTrack &track_toadd,list<FTKTrack> &tracks_list, bool isfirst)
 {
   // remains 0 if the track has to be added
   // -1 means is worse than an old track (duplicated)
@@ -994,30 +960,34 @@ int TrackFitter::doHitWarriorFilter(FTKTrack &track_toadd,list<FTKTrack> &tracks
   int accepted(0);
 
   list<FTKTrack>::iterator itrack = tracks_list.begin();
-
   for (;itrack!=tracks_list.end();++itrack) { // loop over tracks of this bank
 
     // reference to an old track
     FTKTrack &track_old = *itrack;
-    if (track_old.getHWRejected()%10 !=0 || track_old.getHWRejected()/100!=0)
-      // skip HW rejected tracks and tracks with bad chi2,
-      // tracks in removed roads are used, but if a match is found
-      // will be always rejected or marked as removed, if compared
-      // to a combination in a good road
+    if (track_old.getHWRejected()/100 !=0 || ( (!isfirst) && track_old.getHWRejected()%10 !=0) ) //We still want to compare to duplicate tracks
       continue;
 
-    int HWres = track_toadd.HWChoice(track_old,m_HW_dev,m_HW_ndiff,m_HitWarrior);
+    //Slightly different logic on first stage (AUX) vs. 2nd stage (SSB)
+    int HWres = isfirst ? track_toadd.HWChoiceFirstStage(track_old,m_HW_dev,m_HW_ndiff,m_HitWarrior) : track_toadd.HWChoice(track_old,m_HW_dev,m_HW_ndiff,m_HitWarrior);
 
     if (HWres==-1) {
       accepted = -1;
       // passing the end of the list means remove current
-      removeTrack(tracks_list,tracks_list.end(),track_toadd,track_old,true);
+      if (isfirst) { //for first stage processing, don't remove tracks from list yet as they're needed for duplicate removal comparisons
+        removeTrackStage1(tracks_list,tracks_list.end(),track_toadd,track_old,true);
+      } else {
+        removeTrack(tracks_list,tracks_list.end(),track_toadd,track_old,true);
+      }
     }
     else if (HWres==1) {
       accepted = 1;
       // return the new current position, it changes if the
       // rejected track is removed from the list
-      itrack = removeTrack(tracks_list,itrack,track_old,track_toadd);
+      if (isfirst) {
+        itrack = removeTrackStage1(tracks_list,itrack,track_old,track_toadd);
+      } else {
+        itrack = removeTrack(tracks_list,itrack,track_old,track_toadd);
+      }
     }
 
   } // end loop over tracks of this bank
@@ -1025,6 +995,37 @@ int TrackFitter::doHitWarriorFilter(FTKTrack &track_toadd,list<FTKTrack> &tracks
   return accepted;
 }
 
+/** This is the newly added overlap removal method Aux Doctor. It checks the SSIDs,
+    which are extrapolated Aux track coordinates, and performs the overlap removal. **/
+int TrackFitter::doAuxDoctor(FTKTrack &track_toadd,list<FTKTrack> &tracks_list)
+{
+  // remains 0 if the track has to be added
+  // -1 means it's a duplicate
+  int accepted_AuxDoctor(0);
+
+  list<FTKTrack>::iterator itrack = tracks_list.begin();
+
+  for (;itrack!=tracks_list.end();++itrack) { // loop over tracks of this bank
+    // reference to an old track
+    FTKTrack &track_old = *itrack;
+
+    bool toadd = false;
+    for (int i=0; i<track_toadd.getNPlanesIgnored(); i++) {
+      if (track_toadd.getSSID(i) != track_old.getSSID(i)) {
+        toadd = true;
+        break;
+      }
+    }
+
+    if (!toadd) {
+      accepted_AuxDoctor = -1;
+      // passing the end of the list means remove current
+      removeTrack(tracks_list,tracks_list.end(),track_toadd,track_old,true);
+    }
+  } // end loop over tracks of this bank
+
+  return accepted_AuxDoctor;
+}
 
 /** rejected, or mark as rejected, the track in the list
     against  the second track */
@@ -1068,3 +1069,34 @@ list<FTKTrack>::iterator TrackFitter::removeTrack(list<FTKTrack> &tracks_list, l
 
   return itrack;
 }
+
+//Track remover for first stage does not delete tracks, as they are still needed for HW duplciate comparison
+
+list<FTKTrack>::iterator TrackFitter::removeTrackStage1(list<FTKTrack> &, list<FTKTrack>::iterator itrack,
+                          FTKTrack &rejtrk, const FTKTrack &killer, bool rejnew)
+{
+
+  if (!rejnew) { // is rejecting a track in the list
+    if  (rejtrk.getHWRejected()%10==0) { // mark only if not yet marked
+      // mark the old track as rejected
+      rejtrk.setHWRejected( rejtrk.getHWRejected()+1 );
+      // assign the ID of the track rejected this
+      rejtrk.setHWTrackID(killer.getTrackID());
+      //m_nfits_rej += 1;
+    }
+
+  }
+  else {  // is rejecting the new track, not yet in the list
+    if (rejtrk.getHWRejected()%10==0) { // mark only the first time
+      // the new track is rejected
+      // mark the old track as rejected
+      rejtrk.setHWRejected( rejtrk.getHWRejected()+1 );
+      // assign the ID of the track rejected this
+      rejtrk.setHWTrackID(killer.getTrackID());
+
+      //m_nfits_rej += 1;
+    }
+  }
+
+  return itrack;
+}
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter711.cxx b/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter711.cxx
index d59ba14ced35..f54d89484c12 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter711.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/TrackFitter711.cxx
@@ -6,7 +6,6 @@
 #include "TrigFTKSim/TrackFitter711.h"
 #include "TrigFTKSim/MultiTruth.h"
 #include "TrigFTKSim/ftkdefs.h"
-
 #include <TSystem.h>
 
 #include <algorithm>
@@ -17,6 +16,8 @@
 #include <cassert>
 using namespace std;
 
+static int print_guessed=0; //1000;
+
 TrackFitter711::TrackFitter711() :
   TrackFitter(),
   m_use_guessing(true),
@@ -32,7 +33,7 @@ TrackFitter711::TrackFitter711() :
   m_ext_parmask(1<<3), m_idpars(0),
   m_histores_hitcoord_PXL(0),
   m_histores_hitcoord_SCT(0),
-  m_use_SectorDB(false), m_use_multiple_conn(false), m_use_n_conn(999),
+  m_use_SectorDB(false), m_use_multiple_conn(false), m_use_n_conn(999), m_saveIncompleteTracks(false),
   m_resolution_mode(false), m_super_extrapolate(true),
   m_CImap(0), m_CIlayermap(0x0),
   m_resfile(0),
@@ -242,7 +243,8 @@ void TrackFitter711::init()
     m_combtrackI[ic].setNCoords(m_ncoords_incomplete);
     m_combtrackI[ic].setNPlanes(m_nplanes_incomplete);
   }
-  m_complete_maskI = ~(~0u<<m_ncoords_incomplete);
+  unsigned int ones  = ~0;
+  m_complete_maskI = ~(ones<<m_ncoords_incomplete);
 
   m_nplanes_ignored = m_nplanes-m_nplanes_incomplete;
   m_ncoords_ignored = m_ncoords-m_ncoords_incomplete;
@@ -619,6 +621,7 @@ void TrackFitter711::processor_end(int ibank)
   // m_trackoutput_pre_hw->addNFitsHWRejectedMajorityI(ibank,m_nfits_rejmajI);
   // m_trackoutput_pre_hw->addNConnections(ibank,m_nconn);
   // m_trackoutput_pre_hw->addNExtrapolatedTracks(ibank,m_nextrapolatedTracks);
+
 }
 
 
@@ -629,71 +632,71 @@ void TrackFitter711::processor_end(int ibank)
  * Comment:   Called once per road (aka pattern) from a loop in nextEvent()
 *******************************************/
 void TrackFitter711::processor(const FTKRoad &road) {
-
   if (m_resolution_mode) {
-    if (m_HitWarrior_first != 2) {
-      list<FTKTrack> road_tracks; // list 7L tracks for this road
-      // list<FTKTrack> road_tracks_pre_hw; // list 7L tracks before the HW filter
 
-      processor_Incomplete(road,road_tracks);
-      // processor_Incomplete(road,road_tracks, road_tracks_pre_hw);
+    list<FTKTrack> road_tracks; // list 7L tracks for this road
+    list<FTKTrack> road_tracks_pre_hw; // list 7L tracks before the HW filter
 
-      // JAAA not used anymore
-      // processor_ResolutionMode(road,road_tracks);
-    }
-    else{
-      if (m_processor_stage == 1) {
-        processor_Incomplete(road,m_sector_tracks);
-        // JAAA not used anymore
-        // processor_ResolutionMode(road,m_sector_tracks);
-      }
-    }
+    processor_Incomplete(road,road_tracks, road_tracks_pre_hw);
+
+    // JAAA not used anymore
+    //    processor_ResolutionMode(road,road_tracks);
   }
   else {     // performe the fits of the incomplete set of constants
-
-    if (m_HitWarrior_first != 2) {
-      list<FTKTrack> road_tracks; // list 7L tracks for this road
-      // list<FTKTrack> road_tracks_pre_hw; // list 7L tracks before the HW filter
-
-      // perfom the incomplete fit
-      processor_Incomplete(road,road_tracks);
-      // processor_Incomplete(road,road_tracks, road_tracks_pre_hw);
-
-      if (road_tracks.empty()) return;
-
-      // extrapolate and complete the fit
-      if (!m_super_extrapolate)
-        processor_Extrapolate(road,road_tracks);
-      else
-        processor_SuperExtrapolate(road,road_tracks);
-
-      m_tracks_first.splice(m_tracks_first.end(), road_tracks);
-
-    }
-    else {
-      if (m_processor_stage == 1) 
-        processor_Incomplete(road,m_sector_tracks);
-      else if (m_processor_stage == 2) {
-        if (m_sector_tracks.empty()) return;
-        if (!m_super_extrapolate)
-          processor_Extrapolate(road,m_sector_tracks);
-        else 
-          processor_SuperExtrapolate(road,m_sector_tracks);
+    list<FTKTrack> road_tracks; // list 7L tracks for this road
+    list<FTKTrack> road_tracks_pre_hw; // list 7L tracks before the HW filter
+
+    // perfom the incomplete fit
+    processor_Incomplete(road,road_tracks, road_tracks_pre_hw);
+    if (road_tracks.empty()) return;
+
+    if (m_saveIncompleteTracks) {
+      int region = road.getRegion();
+      list<FTKTrack>::iterator itrack = road_tracks.begin();
+      for (;itrack!=road_tracks.end();++itrack) {
+        FTKTrack &track_temp = *itrack;
+        if (m_keep_rejected) { //Add all tracks
+            if ( (*itrack).getHWRejected() == 0) {
+                m_trackoutput->addTrackI(region,*itrack);
+            }
+        } else { //Only add tracks that passed the hit warrior
+            if ( (*itrack).getHWRejected() == 0) {
+                m_trackoutput->addTrackI(region,*itrack);
+            } else {//remove track
+                //3rd and 4th arguments should be arbitrary
+                itrack = removeTrack(road_tracks,itrack,track_temp,track_temp,false);
+            }
+        }
+      }
+      if (m_saveStepByStepTracks) {
+        itrack = road_tracks_pre_hw.begin();
+        for (;itrack!=road_tracks_pre_hw.end();++itrack) {
+          m_trackoutput->addTrackI_pre_hw(region,*itrack);
+        }
       }
+      // itrack = road_tracks_pre_hw.begin();
+      // for (;itrack!=road_tracks_pre_hw.end();++itrack) {
+      //   m_trackoutput_pre_hw->addTrackI(region,*itrack);
+      //      }
     }
+    // extrapolate and complete the fit
+    if (!m_super_extrapolate){
+      processor_Extrapolate(road,road_tracks);
+    }
+    else{
+      processor_SuperExtrapolate(road,road_tracks);
   }
 }
+}
 
 
 /** this method is derived from the standard processor method in the
     TrackFitter class. Basically changes the reference to the incomplete
     constant set and add some details related in the method how the
     incomplete tracks are managed in the current case */
-// void TrackFitter711::processor_Incomplete(const FTKRoad &road,
-//                                           list<FTKTrack> &road_tracks,
-//                                           list<FTKTrack> &road_tracks_pre_hw)
 void TrackFitter711::processor_Incomplete(const FTKRoad &road,
-                                          list<FTKTrack> &road_tracks)
+                                          list<FTKTrack> &road_tracks,
+                                          list<FTKTrack> &road_tracks_pre_hw)
 {
   // check if the road was marked as rejected by the RW or HF
   if (road.getRWRejected()!=0 &&
@@ -792,7 +795,6 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
        if (nhits>m_norecovery_nhits && m_norecovery_nhits!=-1) norecovery_mask |= (1<<p);
      }
    }
-
    m_ncombsI += ncomb;
 
    // m_newtrkI and newtrk are "global", the road related values can be set here
@@ -867,8 +869,10 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
        m_newtrkI.setHWRejected(HWbase);
        m_newtrkI.setHWTrackID(-1);
 
+       if (m_saveStepByStepTracks) m_tracks_hits.push_back(m_newtrkI);
+
        // add one fit in the counters
-       m_nfitsI += 1;
+       if (nmissing==0) m_nfitsI += 1;
        if (nmissing>0) m_nfits_majI += 1;
        if (missPix) m_nfits_majI_pix += 1;
        if (missSCT) m_nfits_majI_SCT += 1;
@@ -880,15 +884,14 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
        bool toAdd(true);
 
        // exact 0 means no valid constants, skipped
-       if( m_newtrkI.getChi2() == 0.)
-         toAdd = false;
+       if( m_newtrkI.getChi2() == 0.) toAdd = false;
+       else if (m_saveStepByStepTracks) m_tracks_pattern.push_back(m_newtrkI);
 
        // majority track with bad chisq have no reason to be kept, recovery is not possible
        if (m_newtrkI.getNMissing() > 0) {
-           // float dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing();
-           float dof = m_ncoords - m_npars - m_newtrkI.getNMissing();
+           float dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing();
            if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
-           float chisqcut = m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut_maj;
+           float chisqcut = m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux : m_Chi2Cut_maj;
            if (m_newtrkI.getChi2()>chisqcut)
              toAdd = false;
        }
@@ -946,11 +949,10 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
        m_newtrkI = theCombos[idx];
        if( m_newtrkI.getNMissing() != 0 ) continue;
 
-       // float dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing(); 
-       float dof = m_ncoords - m_npars - m_newtrkI.getNMissing();
+       float dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing(); //Rui's change to match fw
        if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
-       if( m_newtrkI.getChi2() < ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ) ) {
+       if( m_newtrkI.getChi2() < ( m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux : m_Chi2Cut ) ) {
          fullpassed = true;
          break;
        }
@@ -961,14 +963,14 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
      m_newtrkI = theCombos[idx];
 
      // float dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing();
-     float dof = m_ncoords - m_npars - m_newtrkI.getNMissing();
+     float dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing();
      if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
      // Try to recover majority if chi2 no good
      if (m_newtrkI.getNMissing()==0 &&
          (m_do_majority==1 || (m_do_majority>1 && !fullpassed)) &&
          // Do recovery if chi2 or chi2/dof is above threshold
-         (m_newtrkI.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut )) &&
+         (m_newtrkI.getChi2() > ( m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux : m_Chi2Cut )) &&
          // Or veto majority if chi2 is too high
          (m_newtrkI.getChi2() < m_Chi2Cut_vetomaj || m_Chi2Cut_vetomaj < 0) ) { // recover majority
        /* if the N/N track have a bad chi2 we try to evaluate
@@ -1026,17 +1028,16 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
 
      } // end block to recover complete tracks with bad chi2
 
-     //dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing();
-     dof = m_ncoords - m_npars - m_newtrkI.getNMissing();
+     dof = m_ncoords_incomplete - m_npars - m_newtrkI.getNMissing();
      if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
      // check if the track pass the quality requirements
-     if (m_newtrkI.getChi2()< ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut :
-                             (m_newtrkI.getNMissing() > 0 ? m_Chi2Cut_maj : m_Chi2Cut) )  &&
+     if (m_newtrkI.getChi2()< ( m_Chi2DofCutAux > -1 ? dof*m_Chi2DofCutAux :
+                             (m_newtrkI.getNMissing() > 0 ? dof*m_Chi2DofCutAux : m_Chi2Cut) )  &&
          m_newtrkI.getChi2() != 0 ) {
 
        // appending pre-HW tracks to dump
-       //       road_tracks_pre_hw.push_back(m_newtrkI);
+       road_tracks_pre_hw.push_back(m_newtrkI);
 
        // to append the found track go trought the HW filter
        // add this track to track list only if
@@ -1048,8 +1049,8 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
 
        int accepted(0);
        // Disable hitwarrior, auto-accept every track
-       if (m_HitWarrior!=0 && m_HitWarrior_first!=0)
-         accepted = doHitWarriorFilter(m_newtrkI,road_tracks);
+       if (m_HitWarrior!=0)
+         accepted = doHitWarriorFilter(m_newtrkI,road_tracks,true);//boolean stops duplicate tracks from being removed early for first stage
 
        if (accepted>=0) { // track accepted, no hits shared with already fitted tracks
          // copy m_newtrkI after truth assignment.
@@ -1067,11 +1068,11 @@ void TrackFitter711::processor_Incomplete(const FTKRoad &road,
          // the track is candidate as ghost and is not the best
          // clean the list of the hits
 
-         if (m_keep_rejected) {
-           // copy newtrk after truth assignment.
-           compute_truth_incomplete(region,road,m_newtrkI);
-           road_tracks.push_back(m_newtrkI);
-         }
+         //if (m_keep_rejected) {//Need to keep all until HW duplicate removal is done
+         // copy newtrk after truth assignment.
+         compute_truth_incomplete(region,road,m_newtrkI);
+         road_tracks.push_back(m_newtrkI);
+         //}
          m_nfits_rejI += 1;
          if (nmissing>0) m_nfits_rejmajI += 1;
        }
@@ -1290,23 +1291,42 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
        all hits for previous steps as real*/
     unsigned int cbitmask(m_incomplete_coordsmask_eff);
     m_newtrk.setHalfInvPt(curtrackI.getHalfInvPt());
+    m_newtrk.setInvPtFW(round(curtrackI.getInvPtFW()*1e5)/1e5);
 
     /* Fix from corrgen: in the constant generation, tracks
        in regions 3, 4, and 5 has phi defined in the range [0:2 PI].
        For the extrapolation only checks if the angle is in those
        regions and fix the definition */
-    if (m_ssmap_complete->getRegionMap()->getNumRegions()==8 && region>=3 && region<=5 && curtrackI.getPhi()<=0)
-      m_newtrk.setPhi(curtrackI.getPhi()+2*M_PI,false);
-    else if (m_ssmap_complete->getRegionMap()->getNumRegions()==64 && (region==9 || region==10 || region==25 || region==26 || region==41 || region==42 || region==57 || region==58)  && curtrackI.getPhi()<=0)
-      m_newtrk.setPhi(curtrackI.getPhi());
-    else
+    if (m_ssmap_complete->getRegionMap()->getNumRegions()==8) { // 8 Regions, constant generation step
+      if (region>=3 && region<=5) { // Regions 3, 4, and 5
+        if (curtrackI.getPhi()<=0) { // The angle should be defined in the range [0:2 PI]. Otherwise we fix it.
+          m_newtrk.setPhi(curtrackI.getPhi()+2*M_PI,false);
+          m_newtrk.setPhiFW(round(curtrackI.getPhiFW()+2*M_PI),false);
+        }
+      }
+    }
+    else if (m_ssmap_complete->getRegionMap()->getNumRegions()==64) { // 64 Regions, extrapolation step
+      if (region==9 || region==10 || region==25 || region==26 || region==41 || region==42 || region==57 || region==58) { // Regions 9, 10, 25, 26, 41, 42, 57, and 58
+        if (curtrackI.getPhi()<=0) {
+          m_newtrk.setPhi(curtrackI.getPhi()+2*M_PI,false);
+          m_newtrk.setPhiFW(round(curtrackI.getPhiFW()+2*M_PI),false);
+        }
+      }
+    }
+    else { // In other cases we don't have to force phi to be in the range [0:2 PI].
       m_newtrk.setPhi(curtrackI.getPhi());
+      m_newtrk.setPhiFW(round(curtrackI.getPhiFW()));
+    }
 
     // set the incomplete track with some original info
     m_newtrk.setIP(curtrackI.getIP());
+    m_newtrk.setIPFW(round(curtrackI.getIPFW()));
     m_newtrk.setCotTheta(curtrackI.getCotTheta());
+    m_newtrk.setCTheta(round(curtrackI.getCTheta()));
     m_newtrk.setZ0(curtrackI.getZ0());
+    m_newtrk.setZ0FW(round(curtrackI.getZ0FW()));
     m_newtrk.setChi2(curtrackI.getChi2());
+    m_newtrk.setChi2FW(round(curtrackI.getChi2FW()));
     m_newtrk.setOrigChi2(curtrackI.getOrigChi2());
     m_newtrk.setCombinationID(curtrackI.getCombinationID());
 
@@ -1668,7 +1688,7 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
       // the hits are obtained from the extrapolated SS and the neighbor
       for (int ss_shift=-m_nneighbours/2; ss_shift!=m_nneighbours/2+1; ++ss_shift) {
         const int tmpSS = ssid[ip]+ss_shift*FTKSSMap::getPhiOffset(true,FTKSetup::getFTKSetup().getITkMode());
-	
+  
         // skip SS out of the current module boundaries
         if (/*(ndim==1)&&*/(tmpSS<bounds[ip][0]||tmpSS>bounds[ip][1])) // TODO:
           continue;
@@ -1743,8 +1763,8 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
           cbitmask |= (1<<(m_idcoords_eff[ip]+i));
           cbitmask_real |= (1<<(m_idcoords_eff[ip]+i));
         } else {
-	  if (ndim == 1) missSCT = true;
-	  else missPix = true;
+    if (ndim == 1) missSCT = true;
+    else missPix = true;
           // in this case the extrapolation failed, some empty value is placed
           m_newtrk.setFTKHit(m_idplanes_eff[ip],FTKHit()); // set an empty hit
         }
@@ -1817,14 +1837,14 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
         //for ( int i = 0; i < 16; i++)
         //  std::cout << "m_newtrk.getCoord(" << i << ") = " << m_newtrk.getCoord(i) << std::endl;
 
-        m_nfits += 1;
+        if (nmissing_more==0)m_nfits += 1;
         //std::cout << "m_nfits: " << m_nfits << std::endl;
 
         if (nmissing_more>0) {
           m_nfits_maj += 1;
-	  if (missPix) m_nfits_maj_pix += 1;
-	  if (missSCT) m_nfits_maj_SCT += 1;
-	}
+    if (missPix) m_nfits_maj_pix += 1;
+    if (missSCT) m_nfits_maj_SCT += 1;
+  }
 
         // perform the fit
         //m_newtrk.setTrackID(m_comb_id++);
@@ -1931,7 +1951,7 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
       float dof = m_ncoords - m_npars - m_newtrk.getNMissing();
       if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
-      if( m_newtrk.getChi2() < ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ) )
+      if( m_newtrk.getChi2() < ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut ) )
       {
         fullpassed = true;
         break;
@@ -1959,7 +1979,7 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
     //if (m_extrafits && nmissing_more==0 &&
     //    (m_do_majority==1 || (m_do_majority>1 && !fullpassed)) &&
     //    // Do recovery if chi2 or chi2/dof is above threshold
-    //    (m_newtrk.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut )) &&
+    //    (m_newtrk.getChi2() > ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut )) &&
     //    // Or veto majority if chi2 is too high
     //    (m_newtrk.getChi2() < m_Chi2Cut_vetomaj || m_Chi2Cut_vetomaj < 0) )
 
@@ -1970,8 +1990,8 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
     // Try to recover majority if chi2 no good
     bool do_majority_recover = m_extrafits && nmissing_more==0;
     do_majority_recover = do_majority_recover && (m_do_majority==1 || (m_do_majority>1 && !fullpassed));
-    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ));
-    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ));
+    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut ));
+    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut ));
     do_majority_recover = do_majority_recover && (m_newtrk.getChi2() < m_Chi2Cut_vetomaj || m_Chi2Cut_vetomaj < 0);
 
 
@@ -1981,7 +2001,7 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
          the track using the "best" track within the N combination
          of N-1/N tracks */
       //      FTKSetup::PrintMessageFmt(ftk::info,"pass majority cut");
-      // in this block the used array of track combtrack[] is created
+      // in this block the used array of track m_combtrack[] is created
       // in the init block to save some time
 
       float bestchi2(m_newtrk.getChi2());
@@ -2045,7 +2065,7 @@ void TrackFitter711::processor_Extrapolate(const FTKRoad &road,
     if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
     // check if the track pass the quality requirements
-    if (m_newtrk.getChi2()< ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut :
+    if (m_newtrk.getChi2()< ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB :
           (m_newtrk.getNMissing() > 0 ? m_Chi2Cut_maj : m_Chi2Cut) )  &&
         m_newtrk.getChi2() != 0 )
     {
@@ -2736,11 +2756,11 @@ void TrackFitter711::processor_ResolutionMode(const FTKRoad &road,
       hits_more[ip].clear();
 
       int ndim = m_pmap->getPlane(m_idplanes[ip],0).getNDimension();
-      int m_etaneighbours = (ndim==2) ? m_nneighbours : 0;
+      int etaneighbours = (ndim==2) ? m_nneighbours : 0;
 
       // the hits are obtained from the extrapolated SS and the neighbor
       for (int ss_shift=-m_nneighbours/2; ss_shift!=m_nneighbours/2+1; ++ss_shift) {
-        for (int ss_shiftEta=-m_etaneighbours/2; ss_shiftEta!=m_etaneighbours/2+1; ++ss_shiftEta) {
+        for (int ss_shiftEta=-etaneighbours/2; ss_shiftEta!=etaneighbours/2+1; ++ss_shiftEta) {
 
           const int tmpSS = ssid[ip]+ss_shift*FTKSSMap::getPhiOffset(true,FTKSetup::getFTKSetup().getITkMode())+ss_shiftEta;
 
@@ -2920,7 +2940,7 @@ void TrackFitter711::processor_ResolutionMode(const FTKRoad &road,
         //}
         //std::cout << std::endl;
 
-        // propagating these coordinates to m_newtrk.
+        // propagating these coordinates to newtrk.
         m_newtrk.setCoord(0,0);
         m_newtrk.setCoord(1,0);
         m_newtrk.setCoord(2,m_newtrkI.getCoord(0));
@@ -3013,7 +3033,6 @@ void TrackFitter711::processor_SuperExtrapolate(const FTKRoad &road, list<FTKTra
   list<FTKTrack>::iterator itrack = road_tracks.begin();
 
   for (;itrack!=road_tracks.end();++itrack) {
-    if (itrack->getRoadID() != road.getRoadID()) continue;
     m_newtrkI = *itrack;
     m_passedExtrapolation = false; ///reset this
     extrapolateIncompleteTrack(road);
@@ -3142,7 +3161,12 @@ void TrackFitter711::extrapolateIncompleteTrack(const FTKRoad &road) {
   gatherConnections();
   printConnections();
   bool * iblhits = new bool[m_conn_subregs.size()];
-  
+
+  m_newtrk.setNPlanesIgnored(m_nplanes-m_nplanes_incomplete);
+  for (int ic=0;ic!=m_ncoords;++ic) {
+    m_combtrack[ic].setNPlanesIgnored(m_nplanes-m_nplanes_incomplete);
+  }
+
   for (setIConn(0); m_cur_iconn < (int) m_conn_subregs.size(); setIConn(m_cur_iconn+1)) {
     prepareTrack();
     performExtrapolation();
@@ -3188,23 +3212,42 @@ void TrackFitter711::prepareTrack() {
      all hits for previous steps as real*/
   m_cbitmask = m_incomplete_coordsmask_eff;
   m_newtrk.setHalfInvPt(m_newtrkI.getHalfInvPt());
+  m_newtrk.setInvPtFW(round(m_newtrkI.getInvPtFW()*1e5)/1e5);
 
   /* Fix from corrgen: in the constant generation, tracks
      in regions 3, 4, and 5 has phi defined in the range [0:2 PI].
      For the extrapolation only checks if the angle is in those
      regions and fix the definition */
-  if (m_ssmap_complete->getRegionMap()->getNumRegions()==8 && m_region_for_superexp>=3 && m_region_for_superexp<=5 && m_newtrkI.getPhi()<=0)
-    m_newtrk.setPhi(m_newtrkI.getPhi()+2*M_PI,false);
-  else if (m_ssmap_complete->getRegionMap()->getNumRegions()==64 && (m_region_for_superexp==9 || m_region_for_superexp==10 || m_region_for_superexp==25 || m_region_for_superexp==26 || m_region_for_superexp==41 || m_region_for_superexp==42 || m_region_for_superexp==57 || m_region_for_superexp==58)  && m_newtrkI.getPhi()<=0)
-    m_newtrk.setPhi(m_newtrkI.getPhi());
-  else
-    m_newtrk.setPhi(m_newtrkI.getPhi());
+    if (m_ssmap_complete->getRegionMap()->getNumRegions()==8) { // 8 Regions, constant generation step
+      if (m_region_for_superexp>=3 && m_region_for_superexp<=5) { // Regions 3, 4, and 5
+        if (m_newtrkI.getPhi()<=0) { // The angle should be defined in the range [0:2 PI]. Otherwise we fix it.
+          m_newtrk.setPhi(m_newtrkI.getPhi()+2*M_PI,false);
+          m_newtrk.setPhiFW(round(m_newtrkI.getPhiFW()+2*M_PI),false);
+        }
+      }
+    }
+    else if (m_ssmap_complete->getRegionMap()->getNumRegions()==64) { // 64 Regions, extrapolation step
+      if (m_region_for_superexp==9 || m_region_for_superexp==10 || m_region_for_superexp==25 || m_region_for_superexp==26 || m_region_for_superexp==41 || m_region_for_superexp==42 || m_region_for_superexp==57 || m_region_for_superexp==58) { // Regions 9, 10, 25, 26, 41, 42, 57, and 58
+        if (m_newtrkI.getPhi()<=0) {
+          m_newtrk.setPhi(m_newtrkI.getPhi()+2*M_PI,false);
+          m_newtrk.setPhiFW(round(m_newtrkI.getPhiFW()+2*M_PI),false);
+        }
+      }
+    }
+    else { // In other cases we don't have to force phi to be in the range [0:2 PI].
+      m_newtrk.setPhi(m_newtrkI.getPhi());
+      m_newtrk.setPhiFW(round(m_newtrkI.getPhiFW()));
+    }
 
   // set the incomplete track with some original info
   m_newtrk.setIP(m_newtrkI.getIP());
+  m_newtrk.setIPFW(round(m_newtrkI.getIPFW()));
   m_newtrk.setCotTheta(m_newtrkI.getCotTheta());
+  m_newtrk.setCTheta(round(m_newtrkI.getCTheta()));
   m_newtrk.setZ0(m_newtrkI.getZ0());
+  m_newtrk.setZ0FW(round(m_newtrkI.getZ0FW()));
   m_newtrk.setChi2(m_newtrkI.getChi2());
+  m_newtrk.setChi2FW(round(m_newtrkI.getChi2FW()));
   m_newtrk.setOrigChi2(m_newtrkI.getOrigChi2());
   m_newtrk.setCombinationID(m_newtrkI.getCombinationID());
 
@@ -3279,7 +3322,7 @@ void TrackFitter711::gatherConnections() {
 
       continue;
     } else if (tmpsec>=tmpcon->getNSectors()) {
-      // check if the number of sector is compatible with this bank
+    // check if the number of sector is compatible with this bank
       FTKSetup::PrintMessageFmt(ftk::info,
                                 "*** Complete constants for Sector %d in region %d - %d don't exists\n",
                                 tmpsec,
@@ -3289,7 +3332,7 @@ void TrackFitter711::gatherConnections() {
 
       continue;
     } else if (!tmpcon->getIsGood(tmpsec)) {
-      // check if the sector has a valid constants set
+    // check if the sector has a valid constants set
       FTKSetup::PrintMessageFmt(ftk::info,
                                 "*** Incomplete constants for Sector %d in region %d - %d is not valid\n",
                                 tmpsec,
@@ -3359,10 +3402,10 @@ void TrackFitter711::guessedHitsToSSID() {
     xMax[0]=phiwindow-0.5;
     xMax[1]=etawindow-0.5;
     for (int i=0;i<ndim;++i) {
-      double x=m_newtrk.getCoord(m_idcoords_eff[ip]+i);
-      if(x<0.) x=0.;
-      if(x>xMax[i]) x=xMax[i];
-      tmphit.setCoord(i,x);
+       double x=m_newtrk.getCoord(m_idcoords_eff[ip]+i);
+       if(x<0.) x=0.;
+       if(x>xMax[i]) x=xMax[i];
+       tmphit.setCoord(i,x);
     }
     tmphit.setEtaWidth(etawindow);
     tmphit.setPhiWidth(phiwindow);
@@ -3373,20 +3416,21 @@ void TrackFitter711::guessedHitsToSSID() {
     }
 
     if( FTKSetup::getFTKSetup().getHWModeSS()==2) {
-      try {
-        m_ssid[ip] = m_ssmap_complete->getSSTower
-          (tmphit, tmphit.getBankID(),true);
-      } catch(FTKException &e) {
-        cout<<"TrackFitter711::guessedHitsToSSID bug\n";
-        exit(0);
-      }
+       try {
+          m_ssid[ip] = m_ssmap_complete->getSSTower
+             (tmphit, tmphit.getBankID(),true);
+       } catch(FTKException &e) {
+          cout<<"TrackFitter711::guessedHitsToSSID bug\n";
+          exit(0);
+       }
     }else {
       m_ssid[ip] = m_ssmap_complete->getSSGlobal(tmphit, 1);
     }
 
-
-
-    //    std::cout << "SSID current " << m_ssid[ip] << std::endl;
+    if(print_guessed && (m_idplanes_eff[ip]==0)) {
+       cout<<"guessed_hit: "<< m_ssid[ip]<<":"<<moduleID
+           <<","<<tmphit[0]<<","<<tmphit[1]<<"\n";
+    }
 
     if (ndim == 2) {
 
@@ -3423,44 +3467,44 @@ void TrackFitter711::guessedHitsToSSID() {
         float x = m_newtrk.getCoord(m_idcoords_eff[ip]);
         float y = m_newtrk.getCoord(m_idcoords_eff[ip]+1);
 
-        if( FTKSetup::getFTKSetup().getHWModeSS()==2) {                                                                                                                         
+	 if( FTKSetup::getFTKSetup().getHWModeSS()==2) {                                                                                                                         
           // modify coordinates and get the m_bounds                                                                                                                              
-          tmphit.setCoord(1,0);                                                                                                                                            
-          tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(), true) << std::endl;                                                
-          tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(), true) << std::endl;                                
-          tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(), true) << std::endl;                                               
-          // restore the x-coord                                                                                                                                            
-          tmphit.setCoord(1,y);                                                                                                                                             
-          tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                         
-          tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                               
-          tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                                 
-          // now vary y-cord                                                                                                                                                
-          tmphit.setCoord(1,etawindow);                                                                                                                                        
-          tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                               
-          tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                                  
-          tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                                 
-
-        }                                                                                                                                                                   
-        else {                                                                                            
-
-          // modify coordinates and get the m_bounds
-          tmphit.setCoord(1,0);
-          tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          // restore the x-coord
-          tmphit.setCoord(1,y);
-          tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          // now vary y-cord
-          tmphit.setCoord(1,etawindow);
-          tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-          tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
-        }
+	    tmphit.setCoord(1,0);                                                                                                                                            
+	    tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(), true) << std::endl;                                                
+  	    tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(), true) << std::endl;                                
+  	    tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(), true) << std::endl;                                               
+	    // restore the x-coord                                                                                                                                            
+	    tmphit.setCoord(1,y);                                                                                                                                             
+  	    tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                         
+  	    tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                               
+  	    tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                                 
+	    // now vary y-cord                                                                                                                                                
+	    tmphit.setCoord(1,etawindow);                                                                                                                                        
+  	    tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                               
+  	    tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                                  
+  	    tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSTower(tmphit, tmphit.getBankID(),true) << std::endl;                                                 
+
+	 }                                                                                                                                                                   
+	 else {                                                                                            
+
+        // modify coordinates and get the m_bounds
+        tmphit.setCoord(1,0);
+        tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        // restore the x-coord
+        tmphit.setCoord(1,y);
+        tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        // now vary y-cord
+        tmphit.setCoord(1,etawindow);
+        tmphit.setCoord(0,0);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        tmphit.setCoord(0,x);         std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
+        tmphit.setCoord(0,phiwindow); std::cout << m_ssmap_complete->getSSGlobal(tmphit, 1) << std::endl;
       }
     }
+    }
   }
 }
 
@@ -3472,7 +3516,7 @@ void TrackFitter711::obtainHitsFromSSIDs() {
 
   //std::cout << "Searching hits ...." << std::endl;
 
-  int nError=0,nTry=0;
+   int nError=0,nTry=0;
   // loop to retrieve the hit lists
   for (int ip=0; ip!=m_nplanes_ignored; ++ip) {
     m_hits_more[ip].clear();
@@ -3485,51 +3529,51 @@ void TrackFitter711::obtainHitsFromSSIDs() {
     for (int ss_shift=-m_nneighbours/2; ss_shift!=m_nneighbours/2+1; ++ss_shift) {
       for (int ss_shiftEta=-etaneighbours/2; ss_shiftEta!=etaneighbours/2+1; ++ss_shiftEta) {
 	int tmpSS;
-        if( FTKSetup::getFTKSetup().getHWModeSS()==2) {   
-
-          int phiss =  m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_phiss;	   
-          int phimax=m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_phiwidth;
-          int etass =  0;
-          int etamax=0;
-          int section=0;
-          int localX=0,localY=0;
-          int localModuleID=-1;
-          nTry++;
-          if(ndim ==2)	 {
-            etass =  m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_etass;
-            etamax=m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_etawidth;
-            //the "official" procedure would involve:
-            //decode the SSID into the local anc global coordinates
-            //change the local coordinates as desired
-            //re-encode the SSID
-            m_ssmap_complete->decodeSSTowerXY(m_ssid[ip],m_subreg_for_superexp,m_idplanes_eff[ip],section, localModuleID,localX,localY,true);
+	 if( FTKSetup::getFTKSetup().getHWModeSS()==2) {   
+
+	   int phiss =  m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_phiss;	   
+           int phimax=m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_phiwidth;
+	   int etass =  0;
+           int etamax=0;
+	   int section=0;
+	   int localX=0,localY=0;
+	   int localModuleID=-1;
+           nTry++;
+	   if(ndim ==2)	 {
+              etass =  m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_etass;
+              etamax=m_ssmap_complete->getMap(m_idplanes_eff[ip], 0, 0).m_etawidth;
+	   //the "official" procedure would involve:
+	   //decode the SSID into the local anc global coordinates
+	   //change the local coordinates as desired
+	   //re-encode the SSID
+	     m_ssmap_complete->decodeSSTowerXY(m_ssid[ip],m_subreg_for_superexp,m_idplanes_eff[ip],section, localModuleID,localX,localY,true);
             localX += ss_shift*phiss;
             localY += ss_shiftEta*etass;
             if((localX<0.)||(localX>=phimax)) continue;
             if((localY<0.)||(localY>=etamax)) continue;
             try {
-              tmpSS =  m_ssmap_complete->compressed_ssid_word_pixel(localModuleID,m_idplanes_eff[ip],section,localX,localY,true);
+               tmpSS =  m_ssmap_complete->compressed_ssid_word_pixel(localModuleID,m_idplanes_eff[ip],section,localX,localY,true);
             } catch(FTKException &e) {
-              // coordinates outside module boundary
-              nError++;
-              continue;
+               // coordinates outside module boundary
+               nError++;
+               continue;
             }
-          }else{
-            m_ssmap_complete->decodeSSTowerX(m_ssid[ip],m_subreg_for_superexp,m_idplanes_eff[ip],section, localModuleID,localX,true);
+           }else{
+	     m_ssmap_complete->decodeSSTowerX(m_ssid[ip],m_subreg_for_superexp,m_idplanes_eff[ip],section, localModuleID,localX,true);
             localX += ss_shift*phiss;
             if((localX<0.)||(localX>=phimax)) continue;
   	    try {
-              tmpSS =  m_ssmap_complete->compressed_ssid_word_strip(localModuleID,m_idplanes_eff[ip],section,localX,true);
+               tmpSS =  m_ssmap_complete->compressed_ssid_word_strip(localModuleID,m_idplanes_eff[ip],section,localX,true);
             } catch(FTKException &e) {
-              // coordinates outside module boundary
-              nError++;
-              continue;
+               // coordinates outside module boundary
+               nError++;
+               continue;
             }
-          }
-          //	   tmpSS = m_ssid[ip]+ss_shift*shift+ss_shiftEta;
-          // std::cout << "tmpSS " << tmpSS << std::endl;
-        }
-        else tmpSS = m_ssid[ip]+ss_shift*FTKSSMap::getPhiOffset(isSCT,FTKSetup::getFTKSetup().getITkMode())+ss_shiftEta;
+	   }
+	   //	   tmpSS = m_ssid[ip]+ss_shift*shift+ss_shiftEta;
+	   // std::cout << "tmpSS " << tmpSS << std::endl;
+	 }
+	 else tmpSS = m_ssid[ip]+ss_shift*FTKSSMap::getPhiOffset(isSCT,FTKSetup::getFTKSetup().getITkMode())+ss_shiftEta;
 
         if (getDiagnosticMode()) {
           if (ip==0 && m_ibl_module_with_hit != 0) {
@@ -3564,9 +3608,9 @@ void TrackFitter711::obtainHitsFromSSIDs() {
     //  std::cout << m_hits_more[ip].size() << std::endl;
   } // end loop to retrieve the hit lists
   if(nError>0) {
-    FTKSetup::PrintMessageFmt
-      (ftk::warn,"obtainHitsFromSSIDs nError=%d nTry=%d\n",
-       nError,nTry);
+     FTKSetup::PrintMessageFmt
+        (ftk::warn,"obtainHitsFromSSIDs nError=%d nTry=%d\n",
+         nError,nTry);
   }
 }
 
@@ -3663,7 +3707,7 @@ void TrackFitter711::fitCompleteTracks(const FTKRoad &road) {
       //for ( int i = 0; i < 16; i++)
       //  std::cout << "m_newtrk.getCoord(" << i << ") = " << m_newtrk.getCoord(i) << std::endl;
 
-      m_nfits += 1;
+      if (nmissing_more==0)m_nfits += 1;
       //std::cout << "m_nfits: " << m_nfits << std::endl;
 
       if (nmissing_more>0) {
@@ -3677,6 +3721,9 @@ void TrackFitter711::fitCompleteTracks(const FTKRoad &road) {
       //m_newtrk.setTrackID(m_comb_id++);
       m_newtrk.setTrackID(m_newtrkI.getTrackID());
       m_newtrk.setExtrapolationID(icomb_more);
+
+      for (int ip=0; ip!=m_nplanes_ignored; ++ip) m_newtrk.setSSID(ip,m_ssid[ip]);
+
       m_conn_gcbanks.at(m_cur_iconn)->linfit(m_conn_sectors.at(m_cur_iconn),m_newtrk);
       //std::cout << " Chi2 " <<m_newtrk.getChi2() << std::endl;
       m_newtrk.setOrigChi2(m_newtrk.getChi2());
@@ -3734,14 +3781,13 @@ void TrackFitter711::saveCompleteTracks() {
       float dof = m_ncoords - m_npars - m_newtrk.getNMissing();
       if( dof < 1 ) dof = 1e30; // Just pass all tracks with too few dof
 
-      if( m_newtrk.getChi2() < ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ) ) {
+      if( m_newtrk.getChi2() < ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut ) ) {
         fullpassed = true;
         break;
       }
     }
   }
 
-
   // -------------------------------------------------------------------------
   // N-TRACKS -> SAVE GOOD ONES
   // -------------------------------------------------------------------------
@@ -3767,8 +3813,8 @@ void TrackFitter711::saveCompleteTracks() {
     // Try to recover majority if chi2 no good
     bool do_majority_recover = m_extrafits && nmissing_more==0;
     do_majority_recover = do_majority_recover && (m_do_majority==1 || (m_do_majority>1 && !fullpassed));
-    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ));
-    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut : m_Chi2Cut ));
+    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut ));
+    do_majority_recover = do_majority_recover && (m_newtrk.getChi2() > ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB : m_Chi2Cut ));
     do_majority_recover = do_majority_recover && (m_newtrk.getChi2() < m_Chi2Cut_vetomaj || m_Chi2Cut_vetomaj < 0);
 
 
@@ -3846,15 +3892,24 @@ void TrackFitter711::saveCompleteTracks() {
     //
 
     // check if the track pass the quality requirements
-    if (m_newtrk.getChi2()< ( m_Chi2DofCut > -1 ? dof*m_Chi2DofCut :
-                            (m_newtrk.getNMissing() > 0 ? m_Chi2Cut_maj : m_Chi2Cut) )  &&
+    if (m_newtrk.getChi2()< ( m_Chi2DofCutSSB > -1 ? dof*m_Chi2DofCutSSB :
+          (m_newtrk.getNMissing() > 0 ? m_Chi2Cut_maj : m_Chi2Cut) )  &&
         m_newtrk.getChi2() != 0 )
     {
+
+      // Aux Doctor (Remove extrapolated Aux tracks with the same SSIDs)
+      int accepted_AuxDoctor(0);
+      // Disable Aux Doctor, auto-accept every track
+      if (m_AuxDoctor) accepted_AuxDoctor = doAuxDoctor(m_newtrk,m_tracks);
+
       // to append the found track go trought the HW filter
       // add this track to track list only if
       // don't have common hits with another track,
       // in this case keep the best
 
+      // appending pre-HW tracks to dump
+      m_tracks_pre_hw.push_back(m_newtrk);
+
       // remains 0 if the track has to be added
       // -1 means is worse than an old track (duplicated)
 
@@ -3864,12 +3919,12 @@ void TrackFitter711::saveCompleteTracks() {
       if (m_HitWarrior!=0)
         accepted = doHitWarriorFilter(m_newtrk,m_tracks);
 
-      // track accepted, no hits shared with already fitted tracks
-      if (accepted>=0) {
+      // track accepted, no hits or no SSIDs shared with already fitted tracks
+      if (accepted>=0 && accepted_AuxDoctor==0) {
         if (getDiagnosticMode())
           fillDiagnosticPlotsPerAcceptedTrack();
 
-        // copy m_newtrkI after truth assignment.
+        // copy m_newtrk after truth assignment.
         m_tracks.push_back(m_newtrk);
 
         // removed an existing track
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/atlClustering.cxx b/Trigger/TrigFTK/TrigFTKSim/src/atlClustering.cxx
deleted file mode 100644
index fac21728ebd9..000000000000
--- a/Trigger/TrigFTK/TrigFTKSim/src/atlClustering.cxx
+++ /dev/null
@@ -1,2065 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * atlClusteringLNF
- * ---------------
- *
- * Routines to perform clustering in the pixels.
- *
- * 21-11-2007 Alberto Annovi (alberto.annovi@lnf.infn.it)
- *
- */
-
-#include "TrigFTKSim/FTKSetup.h"
-#include "TrigFTKSim/atlClustering.h"
-#include "TrigFTKSim/FTKPMap.h"
-#include "TrigFTKSim/MultiTruth.h"
-#include "TrigFTKSim/ftkdefs.h"
-#include <boost/circular_buffer.hpp>
-
-#include <cmath>
-#include <cassert>
-#include <iostream>
-#include <iomanip>
-#include <stack>
-#include <queue>
-using namespace std;
-
-#include "TrigFTKSim/ftkdefs.h"
-using ftk::PIXEL;
-using ftk::SCT;
-using ftk::BARREL;
-using ftk::ENDCAP;
-using ftk::POSEC;
-using ftk::NEGEC;
-
-//#define VERBOSE_DEBUG_CLUST
-//#define DEBUG_HITS
-//#define DECODER_INPUT 0
-//#define DECODER_OUTPUT 0
-//#define CLUSTERING_PRINTOUT 0
-//#define CENTROID_PRINTOUT 0
-//#define BOUNDING_BOX
-
-const bool DEBUG_HITS = 0;
-const bool DEBUG_CLUSTERS = 0;
-const bool DEBUG_AVERAGE = 0;
-const bool DEBUG_AVERAGE_SCT = 0;
-
-const bool PRINT_INPUT    = 0; // print input data    
-const bool DEBUG_INPUT    = 0; // detail check input  
-const bool DEBUG_DECODER  = 0; // check decoder output
-const bool DEBUG_CENTROID = 0; // check centroid calc.
-
-const unsigned int MOD_ID_PHI_VAL  = 1;
-const unsigned int MOD_ID_PHI_MASK = 100;
-const unsigned int MOD_ID_ETA_VAL  = MOD_ID_PHI_MASK;
-const unsigned int MOD_ID_ETA_MASK = 100;
-const unsigned int MOD_ID_LAYER_VAL  = MOD_ID_PHI_MASK*MOD_ID_ETA_MASK;
-const unsigned int MOD_ID_LAYER_MASK = 100;
-
-const unsigned int MAX_BARREL_ETA=20;
-const unsigned int MAX_ETA=MAX_BARREL_ETA+6;
-const unsigned int MAX_PHI=56;
-const unsigned int MAX_LAYER_PIXEL=3;
-const unsigned int MAX_LAYER=56;
-
-bool SAVE_CLUSTER_CONTENT;
-bool DIAG_CLUSTERING;
-bool SCT_CLUSTERING;
-int PIXEL_CLUSTERING_MODE;
-bool IBL3D_REALISTIC; //If this boolean is "true", you can get the same IBL 3D centorid as the FTK_IM FW.
-bool DUPLICATE_GANGED;
-bool GANGED_PATTERN_RECOGNITION;
-bool SPLIT_BLAYER_MODULES;
-//bool CLUSTERING_PRINTOUT;
-
-map<int,map<int,int> > module_dup;//ryu added 20160303
-
-/*!
- * Function examining whether a hit is in a specific ROD
- * \param hit the hit to be examined
- * \return true if the hit belongs in the ROD, false otherwise
- */
-bool hitSelector(const FTKRawHit &/*hit*/) {
-    return true;
-    //if (hit.getHitType() == PIXEL && hit.getBarrelEC() == 0 && hit.getLayer()== 1) {
-        //if (hit.getPhiModule() == 13 && (hit.getEtaModule() <= 0))  {
-            //return true;
-        //}
-    //}
-    //else  {
-        //return false;
-    //}
-    //return false;
-}
-
-cluster::~cluster()
-{
-    hitlist.clear();
-}
-
-/*! Function which examines whether a hit belongs to an IBL module. 
- * \param hit the hit
- * \return true if the hit is on an IBL module, false otherwide
- */
-bool hitOnIBLmodule(const FTKRawHit &hit) 
-{
-    int BarrelEndCap = hit.getBarrelEC();
-    int layer = hit.getLayer();
-    bool fixEndcapL0 = FTKSetup::getFTKSetup().getfixEndcapL0();
-    bool isIBLmodule  = FTKSetup::getFTKSetup().getIBLMode()!=0 && layer==0 && (BarrelEndCap==0 || !fixEndcapL0);
-
-    return isIBLmodule;
-}
-
-/**
- * This class creates a hit whose coordinates are relative to the Front-End chip
- * of the module that it belongs to. It is used for the correct ordering of the hits 
- * in the FTK_IM hit decoder. 
- */
-class FTK_FECoordsHit {
-    public:
-    /** 
-     * Create an FTK_Hit_FECoords from an FTKRawHit
-     * \param h FTKRawHit to be processed
-     */
-    FTK_FECoordsHit(const FTKRawHit* hit) {
-        tot = hit->getTot();
-        int acol = hit->getEtaStrip();
-        int arow = hit->getPhiSide();
-	if(!hitOnIBLmodule(*hit)){
-	    if (arow < ftk::clustering::rowsInFEChipPerPixelModuleRow) {
-	         fe = ftk::clustering::feChipsInRowPixel + acol/ftk::clustering::colsInFEChipPerPixelModuleRow;
-	         lrow = arow;
-	         lcol = acol%ftk::clustering::colsInFEChipPerPixelModuleRow;
-	    } else {
-	         fe = (ftk::clustering::feChipsInRowPixel - 1) - acol/ftk::clustering::colsInFEChipPerPixelModuleRow; //-1 because we start counting from 0
-		 lrow = (ftk::numberOfPhiPixelsInPixelModule - 1) - arow; //We start counting from 0
-		 lcol = (ftk::clustering::colsInFEChipPerPixelModuleRow - 1) - acol%ftk::clustering::colsInFEChipPerPixelModuleRow; //Start counting from 0
-	    }
-	}else{
-	  if (acol < ftk::clustering::colsInFEChipPerIblModuleRow) {
-	    fe = 0;
-	    lcol = acol;
-	  } else {
-	    fe = 1;
-	    lcol = acol-80;
-	  }
-	  lrow = (ftk::clustering::rowsInFEChipPerIblModuleRow - 1) - arow;
-	}
-    }
-
-    int fe; ///< The FE chip of the hit
-    int tot; ///< ToT of the hit
-    int lcol; ///< Column of the hit expressed in FE coordinates
-    int lrow; ///< Row of the hit expressed in FE coordinates
-};
-
-/**
- * This class creates a hit whose coordinates are relative to the hit's position
- * in the cluster. It is used to calculate if a cluster is split and for
- * printing out the test vectors. 
- */
-class FTK_ClusterCoordHit
-{
-    public:
-    /** 
-     * Create an FTK_Hit_FECoords from an FTKRawHit
-     * \param h FTKRawHit to be processed
-     * \param seed the central hit of the cluster
-     */
-    FTK_ClusterCoordHit(const FTKRawHit &h, const FTKRawHit* seed) {
-        tot = h.getTot();
-        crow = h.getPhiSide() - (seed->getPhiSide() - 10);
-        if (seed->getEtaStrip() %2 != 0) ccol = h.getEtaStrip() - (seed->getEtaStrip() - 1);
-        else  ccol = h.getEtaStrip() - (seed->getEtaStrip());
-    }
-    int tot; ///<  ToT of the hit in the cluster
-    int ccol; ///< Column of the hit in the cluster
-    int crow; ///< Row of the hit in the cluster
-};
-
-
-bool sortbyFE (const FTKRawHit* i,const  FTKRawHit* j) {
-    if (i->getHitType() == SCT || j->getHitType() == SCT)
-        return false;
-
-    FTK_FECoordsHit lhit1(i);
-    FTK_FECoordsHit lhit2(j);
-
-    if (lhit1.fe != lhit2.fe) return lhit1.fe <= lhit2.fe;
-    else if (lhit1.fe == lhit2.fe) {
-        if (lhit1.lcol/2 != lhit2.lcol/2) return lhit1.lcol/2 <= lhit2.lcol/2;
-        else if (lhit1.lcol/2 == lhit2.lcol/2) return lhit1.lrow < lhit2.lrow;
-    }
-
-    return false;
-}
-
-
-double eta(double px, double py, double pz) {
-    double theta = atan( sqrt(px*px+py*py)/pz );
-    if (theta<0) theta += 3.1415;
-
-    //   std::cout << "px=" << px << " py=" << py << " pz=" << pz
-    // 	    << " theta=" << theta << " eta=" << - log( tan (theta/2) ) << "\n";
-
-    return - log( tan (theta/2) );
-}
-
-double eta(FTKRawHit &hit) {
-    // eta of hit position
-    return eta(hit.getX(), hit.getY(), hit.getZ());
-}
-
-/*!
- * Function examining whether a cluster is split. 
- * \param clu the cluster to be examined
- * \return true if the cluster is split, false otherwise
- */ 
-bool isSplitCluster(const cluster& clu)
-{
-    //FTK_ClusterCoordHit seed = FTK_ClusterCoordHit(*clu.seed, clu.seed);
-    hitVector::const_iterator it = clu.hitlist.begin();
-    for (it = clu.hitlist.begin(); it != clu.hitlist.end(); it++) {
-        if (clu.seed == NULL) 
-            return false;
-        FTK_ClusterCoordHit chit = FTK_ClusterCoordHit(**it , clu.seed);
-        if ((chit.ccol >= GRID_COL_MAX - 1) ||  (chit.crow >= (GRID_ROW_MAX - 1)) || ( chit.crow <= 0))
-	  return true;
-    }
-
-    return false;
-}
-
-void printDebugInfo(FTKRawHit hits)
-{
-  cout << dec 
-       << "HitType "    << hits.getHitType()
-       << " BarrelEC "  << hits.getBarrelEC()
-       << " Layer "     << hits.getLayer()
-       << " IdHash "    << hits.getIdentifierHash()
-       << " PhiModule " << hits.getPhiModule()
-       << " EtaModule " << hits.getEtaModule()
-       << endl;
-}
-
-//#if defined(CLUSTERING_PRINTOUT) || defined(CENTROID_PRINTOUT) || defined(DECODER_INPUT)
-#if defined(CLUSTERING_PRINTOUT) || defined(CENTROID_PRINTOUT) || defined(DECODER_INPUT) || defined(DECODER_OUTPUT)
-
-bool clusterSort (const FTK_ClusterCoordHit &i, const FTK_ClusterCoordHit &j)
-{
-    // reverse the hits on the first row if they are above the seed
-    if (i.ccol == 0 && j.ccol == 0 && i.crow <= 10 && j.crow <= 10)
-        return j.crow <= i.crow;
-    else if (i.ccol == j.ccol)
-        return i.crow <= j.crow;
-    else
-        return i.ccol <= j.ccol;
-}
-
-void printClu(const cluster &clu)
-{
-    hitVector hs = clu.hitlist;
-    hitVector::iterator hit = hs.begin();
-
-    vector<FTK_ClusterCoordHit> tmp;
-    for (hit = hs.begin(); hit != hs.end(); hit++) {
-        tmp.push_back(FTK_ClusterCoordHit(**hit, clu.seed));
-    }
-
-    //sort and print the vector.
-    if (tmp.size() > 1) std::stable_sort(tmp.begin(), tmp.end(), clusterSort);
-
-    for(vector<FTK_ClusterCoordHit>::iterator hit1 = tmp.begin(); hit1 != tmp.end(); hit1++) {
-        printf("0000%.2X%.2X%.3X\n",(*hit1).tot, (*hit1).ccol, (*hit1).crow);
-        //printf("0000%.2X%.2X%.3X",(*hit1).tot, (*hit1).ccol, (*hit1).crow);
-        //printf(" tot: %d col: %d row: %d\n",(*hit1).tot, (*hit1).ccol, (*hit1).crow);
-    }
-
-    int boundary = 2;
-    if (isSplitCluster(clu))
-        boundary = 3;
-
-    if (clu.seed->getEtaStrip() %2 != 0) {
-        printf("000%d00%.2X%.3X\n",boundary, clu.seed->getEtaStrip() - 1, clu.seed->getPhiSide());
-
-        //printf("000%d00%.2X%.3X",boundary, clu.seed->getEtaStrip() - 1, clu.seed->getPhiSide());
-        //printf(" split: %d col: %d row: %d\n",boundary, clu.seed->getEtaStrip() - 1, clu.seed->getPhiSide());
-    }
-    else {
-        printf("000%d00%.2X%.3X\n",boundary, clu.seed->getEtaStrip(), clu.seed->getPhiSide());
-        //printf("000%d00%.2X%.3X",boundary, clu.seed->getEtaStrip(), clu.seed->getPhiSide());
-        //printf(" split: %d col: %d row: %d\n",boundary, clu.seed->getEtaStrip(), clu.seed->getPhiSide());
-    }
-}
-
-void printClusterList(clustersByModuleMap clustersByModule)
-{
-    clustersByModuleMap::iterator p;
-    for (p = clustersByModule.begin(); p!=clustersByModule.end(); ++p) { // loop over modules
-        cluList* cl = (*p).second;
-        cluList::iterator b = cl->begin();
-        FTKRawHit* hit = (*b).hitlist[0];
-        // if (!(hit)->getIsPixel() || hitOnIBLmodule(*hit)) {
-        //     //continue ;
-        // }
-        if (hitSelector(*hit)) {
-            printf("0x200000%02d\n", hitToModuleId(*hit));
-            for (; b != cl->end(); b++) {
-                printClu(*b);
-                //printf("CENTROID: %.8X X: %d Y: %d\n", (*b).clusterEquiv.getHWWord(), (*b).clusterEquiv.getRowCoordinate(), (*b).clusterEquiv.getColumnCoordinate());
-            }
-            printf("0x40000000\n");
-        }
-    // Yoshi 2016.09.29
-    // cout << "isIBLmodule/CluList is " << hitOnIBLmodule(*hit) << endl;
-    // printf("0x200000%02d\n", hitToModuleId(*hit));
-    // for (; b != cl->end(); b++) {
-    //   printClu(*b);
-    //   //printf("CENTROID: %.8X X: %d Y: %d\n", (*b).clusterEquiv.getHWWord(), (*b).clusterEquiv.getRowCoordinate(), (*b).clusterEquiv.getColumnCoordinate());
-    // }
-    // printf("0x40000000\n");
-    }
-}
-
-
-void printCentroidList(clustersByModuleMap clustersByModule)
-{
-    clustersByModuleMap::iterator p;
-    for (p = clustersByModule.begin(); p!=clustersByModule.end(); ++p) { // loop over modules
-        cluList* cl = (*p).second;
-        cluList::iterator b = cl->begin();
-        FTKRawHit* hit = (*b).hitlist[0];
-
-	bool isIBLmodule = hitOnIBLmodule(*hit);
-	int  idHash  = hitToModuleId(*hit);
-	int  isPixel = hit->getIsPixel();
-
-	if(module_dup[isPixel][idHash]==0) // dupli checker ryu 20160303
-	  module_dup[isPixel][idHash]++;
-	else continue; // ryu
-
-        if (hitSelector(*hit)) {
-	  if(isIBLmodule){// for IBL
-	    bool FE0_exist = false;
-	    bool FE1_exist = false;
-
-	    if(hit->getEtaStrip() < 80){
-	      FE0_exist = true;
-	    
-	      b = cl->end() - 1;
-	      int nhit_inCluster = (*b).hitlist.size();
-	      hit = (*b).hitlist[nhit_inCluster-1];
-	      if(hit->getEtaStrip() >= 80)
-		FE1_exist = true;
-	    }else{
-	      FE1_exist = true;
-	    }
-
-	    b = cl->begin();
-	    hit = (*b).hitlist[0];
-
-	    if(FE1_exist == false && FE0_exist == true)
-	      printf("0x08%.7x\n", idHash);
-	    else
-	      printf("0x08%.7x\n", idHash-1);
-	  } else {
-	    printf("0x8%.7x\n", hitToModuleId(*hit));
-	  }
-            for (; b != cl->end(); b++) {
-                //printToFile(outcentroid, (*b).clusterEquiv.getHWWord());
-                printf("0x%.8X ",(*b).clusterEquiv.getHWWord());
-                //std::cout << (*b).clusterEquiv.getTot() << " " << (*b).clusterEquiv.getEtaStrip() << " " << (*b).clusterEquiv.getPhiSide() << std::endl;
-		if (DEBUG_CENTROID) printDebugInfo(*hit);
-            }
-            printf("0x40000000\n");
-        }
-    }
-}
-
-bool sortWords(const FTKRawHit* i, const FTKRawHit* j)
-{
-  int firstCol  = i->getEtaStrip() + 1;
-  int secondCol = j->getEtaStrip() + 1;
-  int firstRow  = 335 - i->getPhiSide(); // Keisuke 20170314, start from 0
-  int secondRow = 335 - j->getPhiSide(); // Keisuke 20170314, start from 0
-
-  if(firstCol != secondCol)      return firstCol < secondCol;
-  else return firstRow > secondRow;
-
-}
-
-//void printDecoderOutput(hitVector* currentHits)
-void printDecoderOutput(hitVector* currentHits, bool isIBLmodule)
-{
-    hitVector::iterator hit = currentHits->begin();
-    hitVector *sortHits = currentHits;
-    int idHash = hitToModuleId(**hit);
-
-    if(isIBLmodule){ // Keisuke 20170215
-      stable_sort(sortHits->begin(), sortHits->end(), sortWords);
-      idHash = hitToModuleId(**sortHits->begin());
-    }
-
-    if(hitSelector(**hit)){
-
-      if(module_dup[(**hit).getIsPixel()][hitToModuleId(**hit)]==0) // dupli checker ryu 20160303
-	module_dup[(**hit).getIsPixel()][hitToModuleId(**hit)]++;
-      else return; // ryu
-
-      if(DEBUG_DECODER) printDebugInfo(**hit);
-
-      if(isIBLmodule){ // for IBL
-	printf("0x8%.7x\n", idHash);
-	//stable_sort(sortHits->begin(), sortHits->end(), sortWords);
-
-	for(hitVector::iterator it = sortHits->begin(); it != sortHits->end(); ++it){
-	  int tempCol = (*it)->getEtaStrip();
-	  // if(tempCol >= 80) tempCol = tempCol - 80; // Yoshi 2016.11.18
-	  int tempRow = 335 - (*it)->getPhiSide(); // Keisuke 20170314, start from 0
-	  int tempTot = (*it)->getTot();
-	  int outputData = ( (tempTot << 20) | (tempCol << 12) | tempRow );
-	  printf("0x0%.7X",outputData);
-
-	  if(!DEBUG_DECODER) cout << endl;
-	  else{
-	    cout << " IBL HIT"
-		 << " col: " << setfill('0') << setw(3) << tempCol
-		 << " row: " << setfill('0') << setw(3) << tempRow
-		 << " tot: " << setfill('0') << setw(2) << tempTot
-		 << endl;
-	  }
-	}
-
-      }else{ // for Pixel
-	printf("0x8%.7x\n", hitToModuleId(**hit));
-	for(hit = currentHits->begin(); hit!= currentHits->end(); hit++) {
-	  printf("0x0%.2X%.2X%.3X",(*hit)->getTot(), (*hit)->getEtaStrip(), (*hit)->getPhiSide());
-	  //std::cout << (*hit)->getTot() << " " << (*hit)->getEtaStrip() << " " << (*hit)->getPhiSide() << std::endl;
-	  if(!DEBUG_DECODER) cout << endl;
-	  else{
-	    cout << " Pixel HIT"
-		 << " col: " << (*hit)->getEtaStrip()
-		 << " row: " << (*hit)->getPhiSide()
-		 << " tot: " << (*hit)->getTot()
-		 << endl;
-	  } 
-
-	} //hit loop
-	printf("0x40000000\n");
-      }
-    }// module check
-}
-#endif
-
-bool sortInput(const FTKRawHit* i, const FTKRawHit* j)
-{
-  int firstCol  = i->getEtaStrip() + 1;
-  int secondCol = j->getEtaStrip() + 1;
-  int firstRow  = 335 - i->getPhiSide(); // Keisuke 20170314, start from 0
-  int secondRow = 335 - j->getPhiSide(); // Keisuke 20170314, start from 0
-  int firstFE  = (firstCol  <= 80) ? 0 : 1;
-  int secondFE = (secondCol <= 80) ? 0 : 1;
-
-  if(firstCol >= 81) firstCol = firstCol - 80;
-  if(secondCol >= 81) secondCol = secondCol - 80;
-
-  if (firstFE != secondFE) return firstFE > secondFE;
-  else{
-    if(firstCol <= 40 || secondCol <= 40){
-      if(firstCol != secondCol)      return firstCol < secondCol;
-      else return firstRow < secondRow;
-    } else {
-      if(firstCol != secondCol)      return firstCol > secondCol;
-      else return firstRow < secondRow;
-    }
-  }
-}
-
-void printInputData(hitVector* currentHits, bool isIBLmodule){
-  hitVector::iterator hit = currentHits->begin();
-  hitVector *sortHits = currentHits;
-  int idHash = hitToModuleId(**hit) + 8;
-  if(isIBLmodule){
-    stable_sort(sortHits->begin(), sortHits->end(), sortInput);
-    idHash = hitToModuleId(**sortHits->begin()) + 8;
-  }
-  //  if(hitSelector(**hit)){
-
-  if(module_dup[(**hit).getIsPixel()][hitToModuleId(**hit)]==0) // dupli checker ryu 20160303
-    module_dup[(**hit).getIsPixel()][hitToModuleId(**hit)]++;
-  else return; // ryu
-
-  if(DEBUG_INPUT) printDebugInfo(**hit);
-
-  if(isIBLmodule){ // for IBL
-    printf("0x03%.1x000000\n", idHash);
-
-    //stable_sort(sortHits->begin(), sortHits->end(), sortInput);
-
-    for(hitVector::iterator it = sortHits->begin(); it != sortHits->end(); ++it){
-      int tempCol = (*it)->getEtaStrip() + 1;
-      if((idHash == 0x8 || idHash == 0xa) && tempCol <= 80){
-	printf("0x05%.1x400000\n", idHash);
-	idHash = idHash + 1;
-	printf("0x03%.1x000000\n", idHash);
-      }
-      if(tempCol >= 81) tempCol = tempCol - 80; // for generate real input
-      int tempRow = 335 - (*it)->getPhiSide(); // Keisuke 20170314, start from 0
-      int tempTot = (*it)->getTot();
-      int outputData = ((idHash << 24) | (tempTot << 20) | (tempCol << 9) | tempRow );
-      printf("0x09%.7x",outputData);
-
-      if(!DEBUG_INPUT) cout << endl;
-      else{
-	cout << " IBL HIT"
-	     << " col: " << setfill('0') << setw(3) << tempCol
-	     << " row: " << setfill('0') << setw(3) << tempRow
-	     << " tot: " << setfill('0') << setw(2) << tempTot
-	     << endl;
-      }
-    }
-
-  }else{ // for Pixel
-
-    printf("0x08%.7x\n", idHash);
-
-    for(hit = currentHits->begin(); hit!= currentHits->end(); hit++) {
-      printf("0x00%.2x%.2x%.3x ",(*hit)->getTot(), (*hit)->getEtaStrip(), (*hit)->getPhiSide());
-
-      if(!DEBUG_DECODER) cout << endl;
-      else{
-	cout << " Pixel HIT"
-	     << " col: " << (*hit)->getEtaStrip()
-	     << " row: " << (*hit)->getPhiSide()
-	     << " tot: " << (*hit)->getTot()
-	     << endl;
-      } 
-    }
-  }   // hit loop
-
-  printf("0x05%.1x400000\n", idHash);
-}
-
-#ifdef BOUNDING_BOX
-void calcBoundingBox(cluster& clu) 
-{
-    int col_min = (clu.hitlist[0])->getEtaStrip();
-    int col_max = (clu.hitlist[0])->getEtaStrip();
-    int row_min = (clu.hitlist[0])->getPhiSide();
-    int row_max = (clu.hitlist[0])->getPhiSide();
-
-    hitVector::iterator hit;
-    for (hit = clu.hitlist.begin(); hit != clu.hitlist.end(); hit++) {
-
-        if ((*hit)->getEtaStrip() < col_min) col_min = (*hit)->getEtaStrip();
-        else if ((*hit)->getEtaStrip() > col_max) col_max = (*hit)->getEtaStrip();
-
-        if ((*hit)->getPhiSide() < row_min) row_min = (*hit)->getPhiSide();
-        else if ((*hit)->getPhiSide() > row_max) row_max = (*hit)->getPhiSide();
-    }
-    std::cout <<  "BOUNDING_BOX" << col_max - col_min + 1 << " " << row_max - row_min + 1<< std::endl;
-}
-#endif
-
-
-/*!
- * Function printing the hit details
- * \param hit the hit 
- * \return void
- */
-void printHit(const FTKRawHit &hit) 
-{
-    std::cout << "DEBUG_HITS: "
-        << "  isPixel=" << hit.getIsPixel()
-        << "  barrel_ec=" << hit.getBarrelEC()
-        << "  layer_disk=" << hit.getLayer()
-        << "  phi_module=" << hit.getPhiModule()
-        << "  eta_module=" << hit.getEtaModule()
-        << "  pi_side=" << hit.getPhiSide()
-        << "  ei_strip=" << hit.getEtaStrip()
-        << "  n_strips=" << hit.getNStrips()
-        << "  deltaPhi=" << hit.getDeltaPhi()
-        << "  deltaEta=" << hit.getDeltaEta()
-        << "  ( x=" << hit.getX()
-        << " y=" << hit.getY()
-        << " z=" << hit.getZ()
-        << " eventindex=" << hit.getEventIndex()
-        << " barcode=" << hit.getBarcode()
-        << " bar_pt=" << hit.getBarcodePt()
-        << " parentage_mask=" << hit.getParentageMask()
-        << " )\n";
-}
-
-/*!
- * Function examining whether the a given row has ganged pixels
- * \param the row to be examined
- * \return true 
- */
-bool pixelRowIsGanged(const int row) 
-{
-    switch (row) {
-        case 153:
-        case 155:
-        case 157:
-        case 159:
-        case 168:
-        case 170:
-        case 172:
-        case 174:
-            return row;        // pixel ganged found (readout channel)
-    }
-    if (160<=row && row<=167)
-        return row;        // pixel ganged found (non readout channel)
-    return false;
-}
-
-/*!
- * Function calculating the module id in which the hit belongs to. 
- * The default mode for now is to check the Identifier Hash of the hit. 
- * \param hit the hit 
- * \return the module id
- *
- */
-int hitToModuleId(const FTKRawHit &hit) {
-
-    if (DEBUG_HITS)
-        printHit(hit);
-
-    //Default mode, return the Identifier Hash of the hit
-    if (hit.getIdentifierHash() > 0 && hit.getHitType() == PIXEL) {
-        return hit.getIdentifierHash();
-    }
-    else if (hit.getIdentifierHash() > 0 && hit.getHitType() == SCT) {
-        return 0x8000 + hit.getIdentifierHash();
-    }
-
-    unsigned int ieta = 0;
-    if (FTKSetup::getFTKSetup().getIBLMode()==1){
-        assert(hit.getEtaModule()>=-8 && hit.getEtaModule()<=8); // cy for ibl
-    }
-    else if (FTKSetup::getFTKSetup().getIBLMode()==2){
-        assert(hit.getEtaModule()>=-10 && hit.getEtaModule()<=10); // version with 3D sensors
-    }
-    else{
-        assert(hit.getEtaModule()>=-6 && hit.getEtaModule()<=6);
-    }
-
-    if (FTKSetup::getFTKSetup().getIBLMode()==1 && hit.getBarrelEC() == ftk::BARREL && hit.getLayer() == 0 && hit.getIsPixel() == 1) { // for ibl
-        // eta index should range -8 to 8 for ibl
-        ieta = 8 + hit.getEtaModule(); // cy was 6
-    } else if (FTKSetup::getFTKSetup().getIBLMode()==2 && hit.getBarrelEC() == ftk::BARREL && hit.getLayer() == 0 && hit.getIsPixel() == 1) { // for ibl
-        // eta index should range -8 to 8 for ibl
-        ieta = 10 + hit.getEtaModule(); // cy was 6
-    }  else if (hit.getBarrelEC() == BARREL){
-        // eta index should range -6 to 6 for barrel
-        ieta = 6 + hit.getEtaModule(); // cy was 6
-    }  else {
-        // eta index should range 0 to 2 for endcaps (just 0 for pixels)
-        assert(hit.getEtaModule()>=0 && hit.getEtaModule()<3);
-        // removed dependency on getIBLMode because it is not needed
-        if (hit.getBarrelEC() == POSEC)
-            ieta = MAX_BARREL_ETA+hit.getEtaModule();
-        if (hit.getBarrelEC() == NEGEC)
-            ieta = MAX_BARREL_ETA+3+hit.getEtaModule();
-    }
-
-    //   if (FTKSetup::getFTKSetup().getIBLMode()==1){
-    //     assert(ieta<MAX_ETA+3); // additions for ibl the first +3 is for ibl (13->16), and the +2 is for ibl (6->8), remove the +2 for 11L ibl
-    //   }
-    //   else {
-    assert(ieta<MAX_ETA);
-    //  }
-
-    unsigned int iphi = hit.getPhiModule();
-    assert(iphi<MAX_PHI);
-
-    unsigned int ilayer = 0;
-    switch (hit.getHitType()) {
-        case PIXEL:
-            ilayer = hit.getLayer();
-            if (FTKSetup::getFTKSetup().getIBLMode()>=1) {
-                assert(ilayer<MAX_LAYER_PIXEL+1); // +1 for ibl layer as pixel
-                break;
-            }
-            else {
-                assert(ilayer<MAX_LAYER_PIXEL);
-                break;
-            }
-            break;
-        case SCT:
-            // for endcaps hit.layer_disk goes from 0 to 17
-            //printHit(hit);
-            ilayer = 10 + hit.getLayer();
-            assert(ilayer>=10 && ilayer<MAX_LAYER);
-            break;
-        default:
-            assert(0);
-    }
-    assert(ilayer<MOD_ID_LAYER_MASK);
-    assert(iphi<MOD_ID_PHI_MASK);
-    assert(ieta<MOD_ID_ETA_MASK);
-
-    unsigned int ModuleId = ilayer*MOD_ID_LAYER_VAL + ieta*MOD_ID_ETA_VAL + iphi*MOD_ID_PHI_VAL;
-
-    if (DEBUG_HITS)
-        std::cout << "  ModuleId=" << ModuleId
-            << "  ilayer=" << ilayer
-            << "  ieta=" << ieta
-            << "  iphi=" << iphi
-            << "\n";
-
-    return ModuleId;
-}
-
-/*!
- * Check (and define) if two hits are next to each other
- * For the time being it accepts only pair of hits from the same module and same SCT side.
- * It crashes if hits are the same.
- * \param hit1 the first hit
- * \param hit2 the second hit
- * \return true if hits are next to each other, false otherwise. 
- */
-bool neighborhood(const FTKRawHit &hit1, const FTKRawHit &hit2) {
-
-    // 1st check same module
-    if (hit1.getBarrelEC() != hit2.getBarrelEC() || hit1.getHitType() != hit2.getHitType() ||
-            hit1.getLayer() != hit2.getLayer() || hit1.getEtaModule() != hit2.getEtaModule() ||
-            hit1.getPhiModule() != hit2.getPhiModule()) { // if module is NOT the same
-        //printHit(hit1);
-        //printHit(hit2);
-        assert(0); // temporary check
-        return false;
-    }
-
-    switch (hit1.getHitType()) {
-        case SCT:
-            if (!SCT_CLUSTERING)
-                return false;
-
-            if (hit1.getPhiSide() != hit2.getPhiSide()) { // if different side
-                assert(0); // temporary check
-                return false;
-            }
-            assert(hit1.getEtaStrip() != hit2.getEtaStrip()); // sanity check
-            //    assert(hit1.getNStrips()==1 && hit2.getNStrips()==1); // should be false some times... just a test
-            //    if (hit1.getEtaStrip() == hit2.getEtaStrip()+1 || hit1.getEtaStrip()+1 == hit2.getEtaStrip())
-            //      return true;
-            if (hit1.getEtaStrip() == hit2.getEtaStrip()+hit2.getNStrips()
-                    || hit1.getEtaStrip()+hit1.getNStrips() == hit2.getEtaStrip())
-                return true;
-            return false;
-
-        case PIXEL:
-            assert(hit1.getEtaStrip() != hit2.getEtaStrip() || hit1.getPhiSide() != hit2.getPhiSide()); // sanity check
-            /* need a common edge, i.e. contiguity along diagonal is not enough (see below) */
-            if ( (hit1.getEtaStrip() == hit2.getEtaStrip()+1 || hit1.getEtaStrip()+1 == hit2.getEtaStrip())
-                    && hit1.getPhiSide() == hit2.getPhiSide()) return true;
-            if ( (hit1.getPhiSide() == hit2.getPhiSide()+1 || hit1.getPhiSide()+1 == hit2.getPhiSide())
-                    && hit1.getEtaStrip() == hit2.getEtaStrip()) return true;
-
-
-            if (DIAG_CLUSTERING) { /* Accept contiguity along diagonal as well */
-                if ( (hit1.getEtaStrip() == hit2.getEtaStrip()+1 || hit1.getEtaStrip()+1 == hit2.getEtaStrip())
-                        && (hit1.getPhiSide() == hit2.getPhiSide()+1 || hit1.getPhiSide()+1 == hit2.getPhiSide()) )
-                    return true;
-            }
-
-            return false;
-    }
-    assert(0); // should not get here!
-    return false;
-}
-
-int buildUpCluster(hitVector *currentHits, cluster &clu) {
-    /*
-     * Recursively adds hits to a given cluster.
-     * Returns number of hits in final cluster.
-     * If no cluster is given (or empty cluster) make a cluster out of the 1st hit.
-     */
-    assert(currentHits->size()>0); // need at least one hit!
-
-    hitVector::iterator hitP;
-    if (clu.hitlist.size()==0) {     // if cluster is empty
-        hitP = currentHits->begin();
-        clu.hitlist.push_back(*hitP);
-        currentHits->erase(hitP);
-
-        // FlagAK - dirty fix to disable clustering on 1st layer
-        //    if( (*hitP).getLayer()==0 && (*hitP).getIsPixel() ) {
-        //      return clu->hitlist.size();
-        //    }
-
-    }
-
-    /* Now we have a non empty cluster */
-    bool newHitsAdded = false;
-    int distanceis = clu.hitlist.size();
-    //for (hitCluP=clu.hitlist.begin(); hitCluP!=clu.hitlist.end(); ++hitCluP) { // loop over hits in cluster
-    for(int i = 0; i < distanceis; i++) {
-        FTKRawHit* hit = clu.hitlist.at(i);
-        for (hitP=currentHits->begin(); hitP!=currentHits->end();) { // loop over hits in module
-            //if (neighborhood(**hitCluP, **hitP)) { // if hits are neighborhood
-            if (neighborhood(*hit, **hitP)) { // if hits are neighborhood
-                // add hit to cluster
-                clu.hitlist.push_back(*hitP);
-                //hitCluP = clu.hitlist.begin();
-                currentHits->erase(hitP);
-                distanceis++;
-                hitP=currentHits->begin(); // if a hit is erased then restart the loop
-                newHitsAdded = true;
-            } else {
-                ++hitP; // if hit is not a neighborhood then go to next hit
-            }
-        } // end of loop over hits in module
-    } // end of loop over hits in cluster
-
-    // if at least one hit was added, check for more neighborhood hits
-    if (newHitsAdded && currentHits->size()) buildUpCluster(currentHits, clu);
-    return clu.hitlist.size();
-}
-
-void makeClustersLNF(hitVector *currentHits, cluList *currentClusters) {
-/*
- * Group all hits from one module into clusters
- */
-
-    int index=0;
-    while (currentHits->size()) { // as long as we have hits
-        cluster clu;
-        clu.isSafe = false;               // initialitaion
-        clu.isKilled = false;             // initialitaion
-        int cluSize = buildUpCluster(currentHits, clu);
-        currentClusters->push_back(clu);
-        if (0)
-            std::cout << "DEBUG_makeCluster:"
-                << "  index=" << index
-                << "  cluSize=" << cluSize
-                << "  Nclusters=" << currentClusters->size()
-                << "\n";
-        index++;
-    }
-}
-
-void makeClusterFromSeed(hitVector *currentHits, cluList *currentClusters, FTKRawHit* &seed) {
-    //erase seed fom currentHits
-    hitVector::iterator position = std::find(currentHits->begin(), currentHits->end(), seed);
-    if (position != currentHits->end()) {
-        currentHits->erase(position);
-    }
-
-    cluster clu;
-    clu.seed = seed;
-    clu.hitlist.push_back(seed);
-    clu.isSafe = false;
-    clu.isKilled = false;
-    if (currentHits->size() > 0) buildUpCluster(currentHits, clu);
-    currentClusters->push_back(clu);
-
-#ifdef BOUNDING_BOX
-    calcBoundingBox(clu);
-#endif
-}
-
-
-bool gangedHitHasNeighborhood(const FTKRawHit &hit, const cluster &clu, hitVector &connectedHits) {
-    bool hasNeighborhood = false;
-    int phi = hitIsGanged(hit);
-    //  std::cout << "phi: " << phi << std::endl;
-    if (phi) { // check hit is ganged
-        int eta = hit.getEtaStrip();
-        hitVector hv = clu.hitlist;
-        hitVector::iterator pp;
-        for (pp=hv.begin(); pp!=hv.end(); ++pp) {
-            if ( eta != (*pp)->getEtaStrip() ) continue;
-            if ( abs(phi - (*pp)->getPhiSide() ) != 1 ) continue;
-            hasNeighborhood = true;
-            FTKRawHit *tmpHit = new FTKRawHit();
-            tmpHit->setHitType( ftk::PIXEL );
-            tmpHit->setModuleType( hit.getModuleType());
-            tmpHit->setEtaStrip( eta );
-            tmpHit->setLayer( hit.getLayer() );
-            tmpHit->setPhiSide( gangedPartner(hit) );
-            if ( !hitIsGanged(*tmpHit) ) {
-                printHit(*tmpHit);
-                assert(0);
-            }
-            connectedHits.push_back( tmpHit ); // store connected hit pointer
-        } // end of nested loop over hits
-    } //end of "if (phi)"
-    return hasNeighborhood;
-}
-
-bool findConnectedGanged(cluster &clu, hitVector &connectedHits) {
-    assert(clu.hitlist.size()>0); // sanity check
-
-    hitVector::iterator p;
-    bool hasNeighborhood = false;
-    for (p=clu.hitlist.begin(); p!=clu.hitlist.end(); ++p) {
-        if ( gangedHitHasNeighborhood(**p, clu, connectedHits) ) {
-            hasNeighborhood = true;
-        }
-    } // end of first loop over hits
-
-    return hasNeighborhood;
-}
-
-bool cluIsGanged(const cluster &clu) {
-    hitVector hv = clu.hitlist;
-    hitVector::iterator p;
-    for (p=hv.begin(); p!=hv.end(); ++p) {
-        if ( hitIsGanged(**p) ) return true;
-    }
-
-    return false;
-}
-
-bool isKilled(const cluster &clu, const hitVector &connectedHits) {
-    hitVector tmphv = clu.hitlist;
-    hitVector::iterator p;
-    for (p=tmphv.begin(); p!=tmphv.end(); ++p) {
-        if ( !hitIsGanged(**p) ) continue;
-        hitVector hv = connectedHits;
-        hitVector::iterator c;
-        for (c=(hv).begin(); c!=(hv).end(); ++c) {
-            assert( hitIsGanged(**c) ); // all connected hits should be ganged !
-            if ( (*c)->getPhiSide() == (*p)->getPhiSide()
-                    && (*c)->getEtaStrip() == (*p)->getEtaStrip() ) return true;
-        }
-    } // loop over hits in cluster
-
-    return false;
-}
-
-/*! 
- * Function calculating the central position of the cluster (i.e. the centroid) for all possible 
- * scenarios (SCT, Pixel, IBL). During the execution of this function, the
- * following variables are set for each cluster: X, Y, Z, 
- *
- * \param cluster the cluster whose average is going to be calculated
- * \return void
- */
-void averageCluster(cluster &clu) {
-    const unsigned int &nHits = clu.hitlist.size();
-    assert(nHits>0); // sanity check
-
-    FTKRawHit &av = clu.clusterEquiv; ///< get pointer to clusterEquivalent
-    FTKRawHit *first = *(clu.hitlist.begin()); ///< get 1st hit
-    // cluster cluSplit = clu; // Yoshi 2016.11.24
-    // FTKRawHit &avSplit = cluSplit.clusterEquiv; ///< get pointer to clusterEquivalent
-
-    /// reset values for clusterEquivalent (alias av)
-    av.reset();
-    av.setX(0);
-    av.setY(0);
-    av.setZ(0);
-    av.setIdentifierHash(first->getIdentifierHash());
-    av.setHitType(first->getHitType());
-    av.setModuleType(first->getModuleType());
-    av.setBarrelEC(first->getBarrelEC());
-    av.setLayer(first->getLayer());
-    av.setPhiModule(first->getPhiModule());
-    av.setEtaModule(first->getEtaModule());
-    av.setEtaStrip(0);
-    av.setNStrips(0);
-    av.setEtaWidth(0);
-    //printf("zeroing from %.8X %d %d\n", av.getHWWord(), av.getEtaWidth(), av.getPhiWidth());
-    av.setPhiWidth(0);
-    av.setIncludesGanged(false);
-
-    int tmp;
-    int etaMax = -1;
-    int etaMin = 4000;
-    int phiMax = -1;
-    int phiMin = 4000;
-    int rowMin = 99999; //int(2*(design->width()/design->phiPitch()))+1;
-    int rowMax = 0;
-    int colMin = 99999; //int(2*(design->length()/design->etaPitch()))+1;
-    int colMax = 0;
-    int qRowMin = 0;  
-    int qRowMax = 0;
-    int qColMin = 0;  
-    int qColMax = 0;
-
-    if (DEBUG_AVERAGE)
-        std::cout << "DEBUG_AVERAGE:  isPixel=" << av.getIsPixel()
-            << ", nHits=" << nHits<< "\n";
-
-    hitVector::iterator p;
-    /// precalculate values for case PIXEL_CLUSTERING_MODE>0
-    int BarrelEndCap = first->getBarrelEC();
-
-    //Calculate the active layer. Start with the layer of the hit. In case 
-    // always count IBL as layer0 and BLayer as layer1
-    int layer = first->getLayer();
-    bool isIBLmodule  = hitOnIBLmodule(*first);
-    bool isIBL_Planar = false;
-    bool isPixelmodule = !isIBLmodule;
-    if (FTKSetup::getFTKSetup().getIBLMode()==0)
-        layer++; 
-    float radius = ftk::clustering::radii[layer];
-
-    //Default values for a pixel module. They are modified for IBL. 
-    float sensorThickness = ftk::sensorThicknessPixel;
-    float etaPitch = ftk::etaPitchPixel;
-    float numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInPixelModule;
-    float lengthOfPixelModuleInUmPixels = ftk::lengthOfPixelModuleIn400umPixels;
-    float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
-    // FlagAA: 2015-01-29 making default the units of 6.25um for r-phi coordinates
-    float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
-    float pixXScaleFactor = ftk::clustering::xScaleFactorPixel;
-    float etaModule = first->getEtaModule()-6;
-    // FlagAA 2013-07-31: IBL code assumes fully planar geometry as in mc12+IBL
-    // This will change for the real detector!!!
-    if (isIBLmodule) {
-        sensorThickness = ftk::sensorThicknessIbl;
-        etaPitch = ftk::etaPitchIbl;
-        numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInIblModule;
-        lengthOfPixelModuleInUmPixels = ftk::lengthOfIblModuleIn250umPixels;
-        moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
-        pixYScaleFactor = ftk::clustering::yScaleFactorIbl; ///<multiply by 10 to count in unit of 25um
-        pixXScaleFactor = ftk::clustering::xScaleFactorIbl;
-        etaModule = first->getEtaModule()-8;
-	isIBL_Planar = (first->getEtaModule() >= -6 && first->getEtaModule() <= 5 ? true : false);
-	if(!isIBL_Planar && IBL3D_REALISTIC){ // 3D
-	  sensorThickness = 230*ftk::micrometer; // 3D
-	  moduleActiveLength = 80*250; // 3D
-	  numberOfEtaPixelsInModule = 80; // 3D
-	}
-    }
-    bool hasGanged = false;
-
-    switch (av.getHitType()) {
-        case SCT: {
-            int firstStrip =  99999;
-            int lastStrip  = -99999;
-            av.setPhiSide(first->getPhiSide());
-            for (p=clu.hitlist.begin(); p!=clu.hitlist.end(); ++p) {
-                av.addX((*p)->getX());
-                av.addY((*p)->getY());
-                av.addZ((*p)->getZ());
-                if ((*p)->getEtaStrip() < firstStrip)
-                    firstStrip = (*p)->getEtaStrip();
-                if ((*p)->getEtaStrip()+(*p)->getNStrips()-1 > lastStrip)
-                    lastStrip = (*p)->getEtaStrip() + (*p)->getNStrips() - 1;
-                av.addEtaStrip((*p)->getEtaStrip());
-                if (DEBUG_AVERAGE_SCT) // && clu.hitlist.size()>1)
-                    printHit(**p);
-            }
-            float stripNumberFloat = (firstStrip*1.+lastStrip)/2;
-            //(av.getEtaStrip()*1.)/nHits;
-            av.setEtaStrip( (int) stripNumberFloat );
-            av.setDeltaPhi( stripNumberFloat - (int) stripNumberFloat );
-            // The convention used for SCT is that we are providing as output
-            // the cluster center minus half a strip (i.e. use the left edge of strip for a single strip cluster)
-            // where output = av.setEtaStrip + av.setDeltaPhi
-            av.setStripCoordinate(firstStrip+lastStrip);
-            av.setColumnCoordinate( 0 );
-            av.setDeltaEta(0);
-            av.setNStrips(lastStrip+1-firstStrip);
-            av.setEtaWidth(1);
-            //std::cout << " strip " << std::endl;
-            av.setPhiWidth(lastStrip+1-firstStrip);
-            if (DEBUG_AVERAGE_SCT) { // && clu.hitlist.size()>1) {
-                std::cout << "SCT AVERAGE: ";
-                printHit(av);
-                std::cout << std::endl;
-            }
-            break; // end of SCT
-            }
-        case PIXEL: {
-            av.setPhiSide(0); // eta is reset a few lines above
-
-	    // HHHHH Different Clustering mode HHHHH
-
-            if (PIXEL_CLUSTERING_MODE == 0) {
-                for (p=clu.hitlist.begin(); p!=clu.hitlist.end(); ++p) { //loop over hits in cluster
-                    assert(av.getLayer()==(*p)->getLayer() && av.getPhiModule()==(*p)->getPhiModule() && av.getEtaModule()==(*p)->getEtaModule() );
-                    if (SAVE_CLUSTER_CONTENT) { // if enabled the cluster also stores also the single channels
-                        FTKRawHit tmpch = *(*p);
-                        // set the barcode of the single channel, this may allow a very refined debugging of
-                        // the cluster content accounting for the single barcode of each channel
-                        MultiTruth mt;
-                        MultiTruth::Barcode uniquecode(tmpch.getEventIndex(),tmpch.getBarcode());
-                        mt.maximize(uniquecode,tmpch.getBarcodePt());
-                        tmpch.setTruth(mt);
-                        av.addChannel(tmpch);
-                    }
-                    av.addX((*p)->getX());
-                    av.addY((*p)->getY());
-                    av.addZ((*p)->getZ());
-                    av.addPhiSide((*p)->getPhiSide());   // phi index
-                    // pixels are counted starting from 0 (left edge) and not 0.5 (center position)
-                    // if only pixel 0 is hit the output value will be 0 and not 0.5 (pixel center)
-                    av.addEtaStrip((*p)->getEtaStrip()); // eta index
-                }
-                tmp = (int)round((av.getEtaStrip()*1.)/nHits);
-                av.setDeltaEta((av.getEtaStrip()*1.)/nHits-tmp);
-                av.setEtaStrip(tmp);
-                tmp = (int)round((av.getPhiSide()*1.)/nHits);
-                av.setDeltaPhi((av.getPhiSide()*1.)/nHits-tmp);
-                av.setPhiSide(tmp);
-                break;
-            }
-
-	    // HHHHH above HHHHH
-
-            /* For PIXEL_CLUSTERING_MODE > 0
-             * calculate cluster center following code at line 701 of
-             * https://svnweb.cern.ch/trac/atlasoff/browser/InnerDetector/InDetRecTools/SiClusterizationTool/trunk/src/MergedPixelsTool.cxx#L701
-             * I.e. m_posStrategy == 1
-             * I.e. use charge imbalance between the two outer most ros (columns) to calculate the centroid
-             * In this code I'll use etaTrack instead of pixel eta for simplicity
-             */
-
-            //std::cout << "CNTRD: CALCULATE CLUSTER" << std::endl;
-            for (p=clu.hitlist.begin(); p!=clu.hitlist.end(); ++p) { //loop over hits in cluster
-                //std::cout << "CNTRD: HIT " << (*p)->getEtaStrip() << " " << (*p)->getPhiSide() << " " << (*p)->getTot()  << std::endl;
-                assert(av.getLayer()==(*p)->getLayer() && av.getPhiModule()==(*p)->getPhiModule() && av.getEtaModule()==(*p)->getEtaModule() );
-
-                if (SAVE_CLUSTER_CONTENT) { // if enabled the cluster also stores also the single channels
-                    FTKRawHit tmpch = *(*p);
-                    // set the barcode of the single channel, this may allow a very refined debugging of
-                    // the cluster content accounting for the single barcode of each channel
-                    MultiTruth mt;
-                    MultiTruth::Barcode uniquecode(tmpch.getEventIndex(),tmpch.getBarcode());
-                    mt.maximize(uniquecode,tmpch.getBarcodePt());
-                    tmpch.setTruth(mt);
-                    av.addChannel(tmpch);
-                }
-
-                av.addX((*p)->getX());
-                av.addY((*p)->getY());
-                av.addZ((*p)->getZ());
-
-                int row = (*p)->getPhiSide();
-                int col = (*p)->getEtaStrip();
-                int tot = (*p)->getTot(); // ToT for pixels
-                if (!isIBLmodule && pixelRowIsGanged(row))
-                    hasGanged = true;
-
-                if (isPixelmodule) {
-                    // account for 600um pixels in the centroid calculation
-                    // will use units of 100um and the convert to normal pixel units below
-                    // will also indicate the center of the pixel instead of the left edge
-                    // considering center of pixel along eta (left (or top if you prefer) edge along phi)
-                    // each FE number is worth 19*400um pixels (400um*16 + 600um*2)
-                    // multiply FE column by 4 to convert to 100um units
-                    int FEnumber = col/ftk::clustering::colsInFEChipPerPixelModuleRow;
-                    int FEcolumn = col%ftk::clustering::colsInFEChipPerPixelModuleRow;
-
-		    if(DEBUG_CENTROID && hitSelector(**p)){
-		      printf("0x00%.2X%.2X%.3X", tot, col, row);
-		      cout << " Pix HIT"
-			   << " FE: " << setfill('0') << setw(2) << FEnumber
-			   << " col: " << setfill('0') << setw(3) << col
-			   << " row: " << setfill('0') << setw(3) << row
-			   << " tot: " << setfill('0') << setw(2) << tot
-			   << " -> ";
-		    }
-
-                    col = FEnumber*(ftk::clustering::colsInFEChipPerPixelModuleRow+1) + FEcolumn;
-                    col *= pixYScaleFactor;
-                    col += pixYScaleFactor/2; // add half a pixel to align to pixel center (assume normal 400um pixel)
-                    col += pixYScaleFactor/2; // assume 1<=FEcolumn<=16 add half a pixel coming from 600um pixel in FEcolumn==0
-                    if (FEcolumn==0) col -= pixYScaleFactor/4; // correct position for first column in FE chip
-                    if (FEcolumn==(ftk::clustering::colsInFEChipPerPixelModuleRow-1)) col += pixYScaleFactor/4; // correct position for last column in FE chip
-                } else if (isIBLmodule) { // IBL case
-		    row = 335 - (*p)->getPhiSide(); // inverse row coordinates // Yoshi 2016.10.28 // JAA updated 17.3.13
-
-		    // if(col >= 80) col = col - 80; // Yoshi 2016.11.18
-
-		    if(DEBUG_CENTROID && hitSelector(**p)){
-		      printf("0x00%.2X%.2X%.3X", tot, col, row);
-		      cout << " IBL HIT"
-			   << " col: " << setfill('0') << setw(3) << col
-			   << " row: " << setfill('0') << setw(3) << row
-			   << " tot: " << setfill('0') << setw(2) << tot
-			   << " -> ";
-		    }
-
-                    //Modifications have to be made to include 3d modules 
-                    int orig_col = col;
-                    col *= pixYScaleFactor; // use units of 25um
-                    col += pixYScaleFactor/2; // add half a pixel to align to pixel center
-		    if((isIBL_Planar && IBL3D_REALISTIC) || !IBL3D_REALISTIC){
-		      if (orig_col==0) col += pixYScaleFactor/2; // add half pixel (500um pixel in col0)
-		      if (orig_col>0) col += pixYScaleFactor; // add a pixel (500um pixel in col0)
-
-		      // for 3D modules only
-		      // if (orig_col==79) col += pixYScaleFactor*5/10; // add 5/10 of pixel i.e. 100um (500um pixel in col79)
-
-		      // for planar modules only
-		      if (orig_col==79) col += pixYScaleFactor*4/10; // add 4/10 of pixel i.e. 100um (450um pixel in col79)
-		      if (orig_col==80) col += pixYScaleFactor*12/10; // add 12/10 of pixel i.e. 300um (450um pixel in col79 and col80)
-		      if (orig_col>80) col += pixYScaleFactor*16/10; // add 16/10 of pixel i.e. 400um (450um pixel in col79 and col80)
-		      if (orig_col==159) col += pixYScaleFactor/2; // add half pixel (500um pixel in col159)
-		    }
-                }
-                row *= pixXScaleFactor;
-
-		// comment 2017.01.30
-		// if(isIBLmodule) row += pixXScaleFactor/2; // applied Manolis' update
-
-		if(DEBUG_CENTROID && hitSelector(**p)){
-		  printf("0x00%.2X%.3X%.3X", tot, col, row);
-		  cout << " Norm."
-		       << " col: " << setfill('0') << setw(3) << col
-		       << " row: " << setfill('0') << setw(4) << row
-		       << " tot: " << setfill('0') << setw(2) << tot
-		       << endl;
-		}
-
-                if (row == rowMin) qRowMin += tot;
-                if (row < rowMin){
-                    rowMin = row;
-                    qRowMin = tot;
-                }
-
-                if (row == rowMax) qRowMax += tot;
-                if (row > rowMax){
-                    rowMax = row;
-                    qRowMax = tot;
-                }
-
-                if (col == colMin) qColMin += tot;
-                if (col < colMin){
-                    colMin = col;
-                    qColMin = tot;
-                }
-
-                if (col == colMax) qColMax += tot;
-                if (col > colMax){
-                    colMax = col;
-                    qColMax = tot;
-                }
-
-		int phi = 335 - (*p)->getPhiSide(); // ROW // JAA updated 13 March 2017 to remove +1 as above
-		// int phi = (*p)->getPhiSide(); // ROW
-		int eta = (*p)->getEtaStrip();          // COLUMN
-
-		if (eta > etaMax) etaMax = eta;
-		if (eta < etaMin) etaMin = eta;
-		if (phi > phiMax) phiMax = phi;
-		if (phi < phiMin) phiMin = phi;
-                // if ((*p)->getEtaStrip() > etaMax) 
-                //     etaMax = (*p)->getEtaStrip();
-                // if ((*p)->getEtaStrip() < etaMin) 
-                //     etaMin = (*p)->getEtaStrip();
-                // if ((*p)->getPhiSide() > phiMax) 
-                //     phiMax = (*p)->getPhiSide();
-                // if ((*p)->getPhiSide() < phiMin) 
-                //     phiMin = (*p)->getPhiSide();
-                if (DEBUG_AVERAGE)
-                    printHit(**p);
-                av.addTot(first->getTot()); // sum ToT for pixel clusters
-            }
-            av.setEtaWidth(etaMax-etaMin+1);
-            av.setPhiWidth(phiMax-phiMin+1);
-
-            // calculate eta index and eta delta
-            double eta_average, phi_average;
-            eta_average = (colMin + colMax) / 2.;
-            phi_average = (rowMin + rowMax) / 2.;
-
-	    // Yoshi added 2017.02.01
-	    // if(colMin == pixYScaleFactor && colMin != colMax) eta_average = (colMin + colMax) / 2. - 1.;
-	    // if(colMax == 1626 && colMin != colMax) eta_average = (colMin + colMax) / 2. - 1.;
-
-	    // New Implementation 
-	   
-	    if (PIXEL_CLUSTERING_MODE == PIXEL_CLUSTERING_HARDWARE) {
-	      float etaRow = -1;
-	      float etaCol = -1;
-	      if(qRowMin+qRowMax > 0) 
-		etaRow = qRowMax/float(qRowMin+qRowMax);
-	      if(qColMin+qColMax > 0) 
-		etaCol = qColMax/float(qColMin+qColMax);
-	      ///	      double test = 0; 
-	      int etaRow32 = 0; 
-	      int etaCol32 =0; 
-	      etaRow32 = lround(etaRow*32); 
-	      etaCol32 = lround(etaCol*32);
-	      int posStrategy = 1; 
-	      if(posStrategy == 1 && !hasGanged && etaRow>0 && etaCol > 0){
-	      if (BarrelEndCap==0) { 
-		phi_average+= lround((getDeltaX1A(clu)+(getDeltaX2A(clu))*etaRow32)/1024.); //  >>10; 
-		
-		if ( (etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5) > 0){
-		  if ( sensorThickness*((etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5) * moduleActiveLength / radius)>etaPitch) {
-		    ///		    test = etaPitch; 
-		    eta_average+= pixYScaleFactor*(etaCol-0.5);
-		    eta_average = lround(eta_average); 
-		  } 
-		  else
-		    eta_average+= lround((getDeltaY1A(clu)+getDeltaY2A(clu)*etaCol32 + getDeltaY1B(clu)*(colMin+colMax) + getDeltaY2B(clu)*etaCol32*(colMin+colMax))/2048.); 
-		}
-		else{ 
-		  if ( sensorThickness*(-1*(etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5) * moduleActiveLength / radius)>etaPitch) {
-		    ///		    test = etaPitch; 
-		    eta_average+= pixYScaleFactor*(etaCol-0.5);
-		    eta_average = lround(eta_average); 
-		  }
-		  else  
-		    eta_average-= lround((getDeltaY1A(clu)+getDeltaY2A(clu)*etaCol32 + getDeltaY1B(clu)*(colMin+colMax) + getDeltaY2B(clu)*etaCol32*(colMin+colMax))/2048.);
-		}
-		
-	      }
-	      
-	      else{
-		phi_average +=  lround((getDeltaXEC1A(clu)+getDeltaXEC2A(clu)*etaRow32)/1024.); 
-		eta_average +=  lround((getDeltaYEC1A(clu)+getDeltaYEC2A(clu)*etaCol32)/1024.); 
-		
-	      }
-	      
-	      }
-	    }
-	    
-	    
-	    
-            //Correction to the eta_average and phi_average used for
-            //PIXEL_CLUSTERING_MODE 1 and 100 
-            if (PIXEL_CLUSTERING_MODE <= PIXEL_CLUSTERING_MIXED) {
-                float pixelEstimateCotTheta = -9999.;
-
-                /* The next lines calculate CotTheta of a hypothetic track starting from ATLAS (0,0,0) 
-                 * and crossing the center of the bounding box of the cluster.
-                 * The Z global position is estimated as: module Z position + cluster Z position within the module.
-                 *  The radius is a fixed costant depending on the layer. It could be better estimated accounting 
-                 *  also for the rphi position within the module.
-                */
-                pixelEstimateCotTheta = (etaModule+(rowMin+rowMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5) * moduleActiveLength / radius;
-                if (PIXEL_CLUSTERING_MODE>=PIXEL_CLUSTERING_IDEAL_APRIL_2014_FIX) /* Fixing an error in the formula */
-                pixelEstimateCotTheta = (etaModule+(colMin+colMax)/2./pixYScaleFactor/numberOfEtaPixelsInModule-0.5) * moduleActiveLength / radius;
-
-
-                // Compute eta for charge interpolation correction (if required)
-                // Two pixels may have tot=0 (very rarely, hopefully)
-                float etaRow = -1;
-                float etaCol = -1;
-                if(qRowMin+qRowMax > 0) 
-                    etaRow = qRowMax/float(qRowMin+qRowMax);
-                if(qColMin+qColMax > 0) 
-                    etaCol = qColMax/float(qColMin+qColMax);
-
-                // Charge interpolation. Very rough guess (one can do better with
-                // candidate track information later) TL
-                //      bool hasGanged = av.getIncludesGanged();
-                float deltax = 0;
-                float deltay = 0;
-                if (BarrelEndCap==0) { //pixelID.is_barrel(elementID)){
-                    deltax = 30*ftk::micrometer*(sensorThickness/(250*ftk::micrometer));
-                    deltay = sensorThickness*fabs(pixelEstimateCotTheta);
-                    if(deltay > etaPitch ){ 
-		      deltay = etaPitch;
-		    }
-                } else {
-                    deltax = 10*ftk::micrometer*sqrt(sensorThickness/(250*ftk::micrometer));
-                    deltay = 10*ftk::micrometer*sqrt(sensorThickness/(250*ftk::micrometer));
-                }
-
-                // Width of the region of charge sharing. For disks assume normal incidence: delta is small, due to diffusion
-                // of drifting charges in silicon. For barrel, assume 10 deg. incidence in Rphi, in z compute from pseudorapidity 
-                // This may be improved with better parameterization, but it is probably better to use candidate track information 
-                // later in reconstruction. TL
-                // Values are made dependent on the sensor thickness to accomodate // different sensors layout. AA
-                //    Point3D<double> globalPos = element->globalPosition(centroid);
-                //    InDetDD::SiLocalPosition totCorrection(0,0,0);
-                int posStrategy = 1; //Same as posStrategy == 1 in InDetRecTools/SiClusterizationTool/trunk/src/MergedPixelsTool.cxx#L701
-                if(posStrategy == 1 && !hasGanged && etaRow>0 && etaCol > 0){
-		  phi_average += pixXScaleFactor*deltax*(etaRow-0.5)/ftk::phiPitch;
-		  eta_average += pixYScaleFactor*deltay*(etaCol-0.5)/etaPitch;
-                } 
-            }
-
-            if (phi_average<0) {
-                assert(phi_average<0);
-                phi_average = 0;
-            }
-            if (eta_average<0) {
-                assert(eta_average<0);
-                eta_average = 0;
-            }
-
-            if (BarrelEndCap!=0) phi_average += ftk::clustering::pixelEndCapRPhiCorrection*pixXScaleFactor;
-            //if (isIBLmodule) phi_average += ftk::clustering::pixelIblRPhiCorrection*pixXScaleFactor; //temp Yoshi 2016.10.07
-	    
-	    // av.setEtaWidth(etaMax-etaMin+1); // duplicate!! needless
-	    // av.setPhiWidth(phiMax-phiMin+1);
-
-		//if (PIXEL_CLUSTERING_MODE == PIXEL_CLUSTERING_HARDWARE) {
-            av.setRowCoordinate( lround(phi_average) );
-		//} else av.setRowCoordinate( lround(phi_average*pixXScaleFactor) );
-            av.setColumnCoordinate( lround(eta_average) );
-            av.setSplit(false);
-
-	    // HHHHH Yoshi 2017.01.10 HHHHH
-            if (PIXEL_CLUSTERING_MODE >= PIXEL_CLUSTERING_MIXED && isSplitCluster(clu)) {
-	      //if (PIXEL_CLUSTERING_MODE >= PIXEL_CLUSTERING_MIXED && !isIBLmodule && isSplitCluster(clu)) {
-                av.setSplit(true);
-            }
-
-            eta_average*=numberOfEtaPixelsInModule/lengthOfPixelModuleInUmPixels/pixYScaleFactor;
-            phi_average/=pixXScaleFactor; // Keisuke 20170314, bug fix of row coordinate range
-            //if (isPixelmodule) {
-                //// rescale full module length 152*400um to the range 0-144
-                //// here 1 units is 400*19/18um (i.e. average 400/600um pixel length)
-                //eta_average*=numberOfEtaPixelsInModule/ftk::lengthOfPixelModuleIn400umPixels/pixYScaleFactor;
-            //} else if (isIBLmodule && FTKSetup::getFTKSetup().getIBLMode()==1) { 
-                //// rescale from 25um units to 250um (1 "normal" IBL pixel) unit
-                //eta_average*=numberOfEtaPixelsInModule/ftk::lengthOfIblModuleIn250umPixels/pixYScaleFactor;
-            //}
-            //else if (isIBLmodule && FTKSetup::getFTKSetup().getIBLMode()==2)
-                //// rescale from 25um units to 250um (1 "normal" IBL pixel) unit
-                //eta_average*=numberOfEtaPixelsInModule/ftk::lengthOfIblModuleIn250umPixels/pixYScaleFactor;
-            //}
-
-            double delta;
-            delta = eta_average - (int) eta_average;
-            av.setDeltaEta(delta);
-            av.setEtaStrip( (int) eta_average );
-            delta = phi_average - (int) phi_average;
-            av.setDeltaPhi(delta);
-            av.setPhiSide( (int) phi_average );
-
-            break; // end of PIXEL
-        }
-        default:
-            assert(0); // should not get here!
-    } // end of switch
-
-    // finally divide by nHits
-    av.divX(nHits);
-    av.divY(nHits);
-    av.divZ(nHits);
-
-    // AB - perform geant parent matching and store with the cluster
-    // data.  this involves passing all raw hits associated with the
-    // cluster to a MultiTruth which will be stored with the hit
-    // when it is converted to an FTKHit.
-    MultiTruth mt;
-    for( hitVector::iterator ihit=clu.hitlist.begin(), fhit=clu.hitlist.end(); ihit!=fhit; ++ihit ) {
-        // record highest pt contribution to the combination (cluster)
-        if( (*ihit)->getTruth() ) {
-            mt.maximize( *((*ihit)->getTruth()) );
-        } else {
-            MultiTruth::Barcode uniquecode((*ihit)->getEventIndex(),
-                    (*ihit)->getBarcode());
-            mt.maximize(uniquecode,(*ihit)->getBarcodePt());
-        }
-    } // end record truth for each raw channel in the cluster
-    clu.clusterEquiv.setTruth(mt);
-
-    if (DEBUG_AVERAGE) {
-        std::cout << "    AVERAGE IS:\n";
-        printHit(av);
-        std::cout << "\n\n";
-    }
-}
-
-void atlClusteringBlayer(vector<FTKRawHit> &hits) {
-    /*
-     * Split blayer modules in half along phi
-     * this effectively makes 22*2=44 modules along phi!
-     */
-    if(!SPLIT_BLAYER_MODULES) return;
-    for(unsigned int i = 0; i < hits.size(); i++) {
-#define HIT hits[i]
-        // AK BLAYER : change # modules in barrel blayer from 22 to 44:
-        if(HIT.getIsPixel() && HIT.getBarrelEC()==ftk::BARREL && HIT.getLayer()==0) {
-            HIT.setPhiModule(HIT.getPhiModule()*2);
-            // mid-module sector division: assume SS=20 or 10.
-            // Then the division is right at SS boundary
-            if(HIT.getPhiSide()>159) HIT.setPhiModule(HIT.getPhiModule()+1); // HARDCODED (328/2 rounded to SS=16)
-        }
-#undef HIT
-    }
-}
-
-
-
-//void realisticPixelDecoder(hitVector* &currentHits)
-void realisticPixelDecoder(hitVector* &currentHits, bool isIBLmodule) //Keisuke 20170215
-{
-    hitVector::iterator hit = currentHits->begin();
-
-#if defined(DECODER_INPUT)
-    printf("0x8%.7x\n", hitToModuleId(*hit));
-    std::cout << "HitType: " << (*hit)->getHitType()  << " Barrel-EC: " << (*hit)->getBarrelEC() <<  " Layer: " << (*hit)->getLayer() << " PhiModule:" << (*hit)->getPhiModule() << " EtaModule: " << (*hit)->getEtaModule() << std::endl;
-    //for (hit = currentHits->begin(); hit!= currentHits->end(); hit++) {
-    //fe_hit fehit = fe_hit((*hit));
-    //printf("0x08%.1X%.2X%.2X%.2X -- %d %d %d", fehit.fe, fehit.tot, fehit.lcol, fehit.lrow , fehit.tot, fehit.lcol, fehit.lrow);
-    //std::cout << " hitType " << (*hit)->getHitType() << " BEC " << (*hit)->getBarrelEC() << " layer " << (*hit)->getLayer() << " phimod " << (*hit)->getPhiModule() << " etamod " << (*hit)->getEtaModule() << std::endl;
-    //}
-#endif
-
-    // if (currentHits->size() > 1)
-    //     std::stable_sort(currentHits->begin(), currentHits->end(), sortbyFE);
-
-    std::stack<FTKRawHit*> lifo;
-    std::queue<FTKRawHit*> fifo;
-
-    if(!isIBLmodule){
-        if (currentHits->size() > 1)
-	    std::stable_sort(currentHits->begin(), currentHits->end(), sortbyFE);
-
-	for(hit = currentHits->begin(); hit != currentHits->end(); hit++) {
-	  if ((*hit)->getPhiSide() <= 163)
-            fifo.push(*hit);
-	  else lifo.push(*hit);
-	}
-
-	currentHits->clear();
-    
-	while(!lifo.empty() && !fifo.empty()){
-	  if ((*lifo.top()).getEtaStrip() <= (*fifo.front()).getEtaStrip()) {
-            currentHits->push_back(lifo.top());
-            lifo.pop();
-	  }
-	  else {
-            currentHits->push_back(fifo.front());
-            fifo.pop();
-	  }
-	}
-
-	while(!lifo.empty()) {
-	  currentHits->push_back(lifo.top());
-	  lifo.pop();
-	}
-	while(!fifo.empty()) {
-	  currentHits->push_back(fifo.front());
-	  fifo.pop();
-	}
-    }else{
-      std::stack<FTKRawHit*> lifo_planar;
-      std::queue<FTKRawHit*> fifo_planar;
-
-      if (currentHits->size() > 1)
-	std::stable_sort(currentHits->begin(), currentHits->end(), sortInput);
-
-      for(hit = currentHits->begin(); hit != currentHits->end(); hit++) {
-	if ((*hit)->getEtaStrip() < 40)
-	  fifo.push(*hit);
-	else if ((*hit)->getEtaStrip() >= 40 && (*hit)->getEtaStrip() < 80)
-	  lifo.push(*hit);
-	else if ((*hit)->getEtaStrip() >= 80 && (*hit)->getEtaStrip() < 120)
-	  fifo_planar.push(*hit);
-	else if ((*hit)->getEtaStrip() >= 120 && (*hit)->getEtaStrip() < 160)
-	  lifo_planar.push(*hit);
-      }
-
-      currentHits->clear();
-
-      while(!fifo.empty()){
-	currentHits->push_back(fifo.front());
-	fifo.pop();     
-      }
-
-      while(!lifo.empty()) {
-	currentHits->push_back(lifo.top());
-	lifo.pop();
-      }
-
-      while(!fifo_planar.empty()) {
-	currentHits->push_back(fifo_planar.front());
-	fifo_planar.pop();
-      }
-
-      while(!lifo_planar.empty()) {
-	currentHits->push_back(lifo_planar.top());
-	lifo_planar.pop();
-      }
-    }// if isIBLmodule  
-
-}
-
-
-//FTKRawHit* gridAUTH( boost::circular_buffer<FTKRawHit*> &cb, hitVector &fifo, hitVector &gridhits)
-FTKRawHit* gridAUTH( boost::circular_buffer<FTKRawHit*> &cb, hitVector &fifo, hitVector &gridhits, bool isIBLmodule)
-{
-    //seed is set from cb if there are hits and from
-    //fifo if the seed is empty.
-    FTKRawHit* seed = fifo.front();
-    if (cb.size() != 0) {
-        boost::circular_buffer<FTKRawHit*>::iterator cbi = cb.begin();
-        seed = *cbi;
-        for( cbi = cb.begin(); cbi != cb.end(); cbi++){
-            if ((*cbi)->getEtaStrip() < seed->getEtaStrip())
-                seed  = *cbi;
-            else if ((*cbi)->getEtaStrip() == seed->getEtaStrip()) {
-	      //if ((*cbi)->getPhiSide() < seed->getPhiSide())
-	        if ((*cbi)->getPhiSide() < seed->getPhiSide() && !isIBLmodule) //Keisuke 20170215
-                    seed = *cbi;
-		else if ((*cbi)->getPhiSide() > seed->getPhiSide() && isIBLmodule)
-		    seed = *cbi;
-            }
-        }
-    }
-
-    //step 2: set grid window limits
-    int gridStrCol ;
-    if (seed->getEtaStrip() % 2 != 0) gridStrCol = seed->getEtaStrip() - 1;
-    else gridStrCol = seed->getEtaStrip();
-    int gridCntRow = seed->getPhiSide();
-
-    //step 3: put hits from cb to the grid window
-    int dist = distance(cb.begin(), cb.end());
-    for(int i = 0; i < dist; i++) {
-        FTKRawHit* h = cb.front();
-        if (!hitColInGrid(gridStrCol, h)) {
-            cb.pop_front();
-            continue;
-        }
-        if (hitRowInGrid(gridCntRow, h))
-            gridhits.push_back(h);
-        else
-            cb.push_back(h);
-        cb.pop_front();
-    }
-
-    //step 4: put hits from fifo to the grid window
-    hitVector::iterator fifo_it = fifo.begin();
-    while (fifo_it != fifo.end()) {
-        FTKRawHit* hit = *fifo_it;
-        if (!hitColInGrid(gridStrCol, hit))
-            break;
-        if (hitRowInGrid(gridCntRow, hit))
-            gridhits.push_back(hit);
-        else
-            cb.push_back(hit);
-        fifo.erase(fifo_it);
-    }
-
-    return seed;
-}
-
-
-/*!
- * Function responsible for hit clustering and the subsequent centroid
- * calculation 
- * \param hits hits which will be clustered
- * \return void
- */
-void atlClusteringLNF(vector<FTKRawHit> &hits)
-{
-    /*
-     * make clusters in every module
-     */
-    hitsByModuleMap hitsByModule; ///< store hits by module
-    hitsByModuleMap hitsByModuleFrozen; ///< store hits by module
-
-    // Temporary storage for duplicate copy of ganged pixels
-    // Automatically deleted at the end of this function
-    std::vector<FTKRawHit> gangedPixelList;
-    gangedPixelList.reserve(hits.size()); // reserve memory in excess
-
-    /*
-     * First: organize raw hits by module
-     */
-    vector<FTKRawHit> sortHits;
-
-    for(unsigned int i = 0; i < hits.size(); i++) {
-        int modId = hitToModuleId(hits[i]);
-
-        if (modId>=0) {
-            hitsByModule[modId].push_back( &(hits[i]) );
-            if (DUPLICATE_GANGED && hitIsGanged(hits[i])) {
-                //use the copy constructor instead of manually assigning each
-                //variable, as was done previously. the usage here is the
-                //whole point of having a copy constructor!
-                gangedPixelList.push_back( hits[i] );
-                FTKRawHit &lastPointer = gangedPixelList.back();
-                lastPointer.setPhiSide(gangedPartner( hits[i] ));
-                hitsByModule[modId].push_back( &lastPointer );
-            }
-        } else {
-            assert(0); // should not need this any more
-        }
-    }
-
-#ifdef HAVE_ROOT
-    if(ROOTOUTCLU) rootOutput_clu_moduleStat(hitsByModule);
-#endif
-#ifdef VERBOSE_DEBUG_CLUST
-    std::cout << "Ready to do clusters\n";
-#endif
-
-    /*
-     * Second: build the list of clusters
-     */
-    clustersByModuleMap clustersByModule; ///< store clusters by module
-    hitsByModuleFrozen = hitsByModule; ///< keep hits structure
-    hitsByModuleMap::iterator p;
-
-    // #if defined(DECODER_OUTPUT) // control word (begin) // Yoshi 2016.10.01
-    // 	cout << "0x1B0F00000" << endl;
-    // #endif
-
-    for (p = hitsByModule.begin(); p!=hitsByModule.end(); ++p) { // loop over modules
-        hitVector *currentHits = & (p->second);
-        FTKRawHit &firstHit = **(currentHits->begin());
-        int modId = hitToModuleId( firstHit );
-
-	bool isIBLmodule  = hitOnIBLmodule(firstHit); // Yoshi 2016.09.29
-
-	if(PRINT_INPUT)
-	  printInputData(currentHits, isIBLmodule);
-
-#if defined(DECODER_OUTPUT)
-	printDecoderOutput(currentHits, isIBLmodule);
-	//printDecoderOutput(currentHits);
-#endif
-        //bool isIBLmodule  = hitOnIBLmodule(firstHit);
-        //bool isIBLmodule = FTKSetup::getFTKSetup().getIBLMode()!=0 && firstHit.getLayer()==0;
-        cluList *currentClusters = new cluList(); // instantiate cluster list
-        clustersByModule[modId] = currentClusters;
-
-        //The ideal clustering is going to be used in the following cases: 
-        //1. PIXEL_CLUSTERING_MODE is less than 100 (PIXEL_CLUSTERING_MIXED)
-        //2. The module is not a pixel module
-
-	// HHHHH Yoshi 2017.01.10 HHHHH
-        if (PIXEL_CLUSTERING_MODE < PIXEL_CLUSTERING_MIXED || !firstHit.getIsPixel()) {
-	  //if (PIXEL_CLUSTERING_MODE < PIXEL_CLUSTERING_MIXED || !firstHit.getIsPixel() || isIBLmodule) {
-            makeClustersLNF(currentHits, currentClusters); // use ideal clustering
-        }
-        else { // PIXEL_CLUSTERING_MODE >= 100 and pixel module 
-	  //realisticPixelDecoder(currentHits);
- 	    realisticPixelDecoder(currentHits, isIBLmodule);
-
-            boost::circular_buffer<FTKRawHit*> circular_buffer (256);
-            hitVector gridhits;
-            hitVector fifo = *currentHits;
-            while (!fifo.empty() || !circular_buffer.empty()) {
-	        //FTKRawHit* seed = gridAUTH(circular_buffer, fifo, gridhits);
-	      FTKRawHit* seed = gridAUTH(circular_buffer, fifo, gridhits, isIBLmodule);
-                makeClusterFromSeed(&gridhits, currentClusters, seed);
-
-                for(hitVector::iterator hsi = gridhits.begin(); hsi != gridhits.end(); hsi++) {
-                    circular_buffer.push_back(*hsi);
-                }
-
-                gridhits.clear();
-            }
-        }
-
-        if (DEBUG_CLUSTERS) {
-            std::cout << "DEBUG_CLUSTERS:"
-                << "  modId=" << modId
-                << "  HitListSize=" << currentHits->size()
-                << "  ClusterListSize=" << currentClusters->size()
-                << "\n";
-        }
-    } // end of loop over modules
-
-    // #if defined(DECODER_OUTPUT) // control word (end) // Yoshi 2016.10.01
-    // 	cout << "0x2E0F00000" << endl;
-    // #endif
-
-#ifdef VERBOSE_DEBUG_CLUST
-    std::cout << "Clusters made\n";
-#endif
-
-#if defined(CLUSTERING_PRINTOUT)
-    printClusterList(clustersByModule);
-#endif
-
-    /*
-     * Third: take the "average" of each cluster
-     */
-    int nTotClu = 0;
-    clustersByModuleMap::iterator cluModP; // loop over modules
-    for (cluModP=clustersByModule.begin(); cluModP!=clustersByModule.end(); cluModP++) {
-        hitVector connectedHits; // list of ganged hits that are connected to a confirmed ganged hit
-        cluList::iterator cluP;
-        for (cluP=cluModP->second->begin(); cluP!=cluModP->second->end(); cluP++) {
-            // do pattern recognition in the ganged region
-            if ( (*cluP->hitlist.begin())->getIsPixel() && findConnectedGanged(*cluP, connectedHits) ) // set isSafe
-                cluP->isSafe = true;
-        }
-
-        for (cluP=cluModP->second->begin(); cluP!=cluModP->second->end(); cluP++) {
-            if ( (*cluP->hitlist.begin())->getIsPixel() && isKilled(*cluP, connectedHits) ) // set isKilled
-                cluP->isKilled = true;
-            averageCluster(*cluP); // use floating-point average
-            nTotClu++; // count all clusters
-        }
-
-        // delete connected hits
-        hitVector::iterator connectedP;
-        for (connectedP = connectedHits.begin(); connectedP!=connectedHits.end(); ++connectedP) {
-            delete *connectedP;
-        }
-    }
-
-#ifdef VERBOSE_DEBUG_CLUST
-    std::cout << "Ready to call rootOutput_clu_moduleClusterStat\n";
-#endif
-#ifdef HAVE_ROOT
-    if(ROOTOUTCLU) rootOutput_clu_moduleClusterStat(clustersByModule, hitsByModuleFrozen, event);
-#endif
-
-#ifdef VERBOSE_DEBUG_CLUST
-    std::cout << "Averages made\n";
-#endif
-
-#if defined(CENTROID_PRINTOUT)
-    printCentroidList(clustersByModule);
-#endif
-
-    /*
-     * Fourth: put clusters/hits back in the event hit list
-     */
-    hits.clear();
-
-    int hitCounter=0;
-    int deletedGangedClusters=0;
-    for (cluModP=clustersByModule.begin(); cluModP!=clustersByModule.end(); cluModP++) {
-        cluList::iterator cluP;
-        for (cluP=cluModP->second->begin(); cluP!=cluModP->second->end(); cluP++) {
-            // kill clusters with ganged hits according to ganged pattern recognition
-            if ( GANGED_PATTERN_RECOGNITION && cluP->isKilled && !cluP->isSafe ) {
-                // AA 2009-07-07 removing the "isSafe" protection does not change
-                // number of combinations to fit for single muon events
-                deletedGangedClusters++;
-                continue;
-            }
-
-            // store hit by value
-            FTKRawHit cluEquiv = (*cluP).clusterEquiv;
-            hits.push_back(cluEquiv);
-            ++hitCounter;
-        }
-        delete cluModP->second;
-    }
-    assert( (hitCounter+deletedGangedClusters) == nTotClu );
-
-#ifdef VERBOSE_DEBUG_CLUST
-    std::cout << "Added clusters to the event hit list\n";
-#endif
-
-    /*
-     * Fifth: free memory (could optimize and do this in previous step)
-     */
-
-    // The atlhit data from event is allocated and destroyed outside this function.
-    // clustersByModuleMap is automatically deleted.
-    clustersByModule.clear();
-
-#ifdef VERBOSE_DEBUG_CLUST
-    std::cout << "Deleted cluster structure\n\n";
-#endif
-}
-
-/*!
- * Function examining if a hit is ganged. In case the hit belongs to a pixel
- * module and at a row with ganged pixels, the phi coordinate of the pixel is
- * returned. It always returns 0 if the hit belongs to an IBL module. 
- * \param hit hit to be examined
- * \return The phi coordinate of the hit if the hit is ganged, 0 otherwise
- */
-int hitIsGanged(const FTKRawHit &hit) {
-    if (FTKSetup::getFTKSetup().getIBLMode()>=1 && hit.getLayer()==0)
-        return 0; // FlagAA: IBL is never ganged
-    if (hit.getIsPixel()) {
-        int phi = hit.getPhiSide();
-        if (pixelRowIsGanged(phi))
-            return phi;
-    }
-    return 0;
-}
-
-
-int gangedPartner(const FTKRawHit &hit) {
-    if (hit.getIsPixel()) {
-        switch (hit.getPhiSide()) {
-            case 153:
-                return 160;
-            case 160:
-                return 153;
-            case 155:
-                return 161;
-            case 161:
-                return 155;
-            case 157:
-                return 162;
-            case 162:
-                return 157;
-            case 159:
-                return 163;
-            case 163:
-                return 159;
-            case 168:
-                return 164;
-            case 164:
-                return 168;
-            case 170:
-                return 165;
-            case 165:
-                return 170;
-            case 172:
-                return 166;
-            case 166:
-                return 172;
-            case 174:
-                return 167;
-            case 167:
-                return 174;
-            default:
-                return hit.getPhiSide();
-        }
-    }
-    return -1;
-}
- 
-double getDeltaX1A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  float pixXScaleFactor = ftk::clustering::xScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
-  float sensorThickness = ftk::sensorThicknessPixel;
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;
-  }
-  return lround(-(32*32*(30*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch)/2.));
-  
-}
-double getDeltaX2A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float pixXScaleFactor = ftk::clustering::xScaleFactorPixel; 
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;
-  }
-  return lround(32*(30*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch));  
-}
-int getDeltaXEC1A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float pixXScaleFactor = ftk::clustering::xScaleFactorPixel; 
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;
-  }
-  return lround(- (32*32*(10*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch)/2.)); 
-}
-int getDeltaXEC2A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float pixXScaleFactor = ftk::clustering::xScaleFactorPixel; 
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;
-  }
-  return lround(32*(10*ftk::micrometer*pixXScaleFactor*(sensorThickness/(250*ftk::micrometer))/ftk::phiPitch));
-}
-int getDeltaYEC1A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float etaPitch = ftk::etaPitchPixel;
-  float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; 
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;
-    etaPitch = ftk::etaPitchIbl;
-  }
-  return lround(- (32*32*(10*ftk::micrometer*pixYScaleFactor*(sensorThickness/(250*ftk::micrometer))/etaPitch)/2.)); 
-}
-int getDeltaYEC2A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float etaPitch = ftk::etaPitchPixel;
-  float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; 
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;
-    etaPitch = ftk::etaPitchIbl;
-  }
-  return lround(32*(10*ftk::micrometer*pixYScaleFactor*(sensorThickness/(250*ftk::micrometer))/etaPitch));
-}
-int getDeltaY1A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  int layer = first->getLayer();
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  if (FTKSetup::getFTKSetup().getIBLMode()==0)
-    layer++; 
-  float radius = ftk::clustering::radii[layer];
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float etaPitch = ftk::etaPitchPixel;
-  float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
-  float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
-  float etaModule = first->getEtaModule()-6;
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
-    moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
-    pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 10 to count in unit of 25um
-    etaModule = first->getEtaModule()-8;
-    etaPitch = ftk::etaPitchIbl;
-    
-  } 
-  return lround ( - 32*32*2* pixYScaleFactor*sensorThickness* etaModule*moduleActiveLength/radius /etaPitch/2. ) + lround( 32*32*2* pixYScaleFactor*sensorThickness*moduleActiveLength/radius /etaPitch/2/2);  
-}
-int getDeltaY2A(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  int layer = first->getLayer();
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  if (FTKSetup::getFTKSetup().getIBLMode()==0)
-    layer++; 
-  float radius = ftk::clustering::radii[layer];
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float etaPitch = ftk::etaPitchPixel;
-  float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
-  float pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 16 to count in unit of 25um
-  float etaModule = first->getEtaModule()-6;
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
-    moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
-    pixYScaleFactor = ftk::clustering::yScaleFactorPixel; ///<multiply by 10 to count in unit of 25um
-    etaModule = first->getEtaModule()-8;
-    etaPitch = ftk::etaPitchIbl;
-  }
-  return lround (32*2* pixYScaleFactor*sensorThickness* etaModule*moduleActiveLength/radius /etaPitch) + lround ( - 32*2* pixYScaleFactor*sensorThickness* moduleActiveLength/radius /etaPitch/2.);  
-}
-
-int getDeltaY1B(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  int layer = first->getLayer();
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  if (FTKSetup::getFTKSetup().getIBLMode()==0)
-    layer++; 
-  float radius = ftk::clustering::radii[layer];
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float etaPitch = ftk::etaPitchPixel;
-  float numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInPixelModule;
-  float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
-    numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInIblModule;
-    moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
-    etaPitch = ftk::etaPitchIbl;
-  }
-  return  lround ( - 32*32* sensorThickness/numberOfEtaPixelsInModule *moduleActiveLength/radius /etaPitch/2);
-}
-int getDeltaY2B(cluster &clu){
-  FTKRawHit *first = *(clu.hitlist.begin());
-  int layer = first->getLayer();
-  bool isIBLmodule  = hitOnIBLmodule(*first);
-  if (FTKSetup::getFTKSetup().getIBLMode()==0)
-    layer++; 
-  float radius = ftk::clustering::radii[layer];
-  float sensorThickness = ftk::sensorThicknessPixel;
-  float etaPitch = ftk::etaPitchPixel;
-  float numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInPixelModule;
-  float moduleActiveLength = ftk::lengthOfPixelModuleIn400umPixels*ftk::etaPitchPixel/ftk::micrometer;
-  if (isIBLmodule) {
-    sensorThickness = ftk::sensorThicknessIbl;etaPitch = ftk::etaPitchIbl;
-    numberOfEtaPixelsInModule = ftk::numberOfEtaPixelsInIblModule;
-    moduleActiveLength = ftk::lengthOfIblModuleIn250umPixels*ftk::etaPitchIbl/ftk::micrometer; // planar sensors
-    etaPitch = ftk::etaPitchIbl;
-  }
-  return lround (32 * sensorThickness/numberOfEtaPixelsInModule *moduleActiveLength/radius/etaPitch ) ; 
-}	   
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/components/TrigFTKSim_entries.cxx b/Trigger/TrigFTK/TrigFTKSim/src/components/TrigFTKSim_entries.cxx
index 03291a2244d9..6448c218a3ac 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/components/TrigFTKSim_entries.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/components/TrigFTKSim_entries.cxx
@@ -1,3 +1,6 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
 #include "TrigFTKSim/FTKRoadFinderAlgo.h"
 #include "TrigFTKSim/FTKDumpCondAlgo.h"
 #include "TrigFTKSim/FTKTrackFitterAlgo.h"
diff --git a/Trigger/TrigFTK/TrigFTKSim/src/tsp/FTKTSPBank.cxx b/Trigger/TrigFTK/TrigFTKSim/src/tsp/FTKTSPBank.cxx
index c8ec09cc4c73..6454874e2a38 100644
--- a/Trigger/TrigFTK/TrigFTKSim/src/tsp/FTKTSPBank.cxx
+++ b/Trigger/TrigFTK/TrigFTKSim/src/tsp/FTKTSPBank.cxx
@@ -24,6 +24,9 @@ using __gnu_cxx::hash_map;
 #define PRINT_ROADS_SECTOR -1
 #define PRINT_ROADS_NUM 100
 
+#define PRINT_ROADS_SECTOR -1
+#define PRINT_ROADS_NUM 100
+
 FTKTSPBank::FTKTSPBank(int bankid, int subid) :
     FTK_AMBank(bankid, subid),
     m_TSPProcessor(0x0),
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.cc
index 7f0efae21f1e..83ab405e54b7 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.cc
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.cc
@@ -8,9 +8,9 @@
 #include <iomanip>
 #include <cmath>
 #include <TFile.h>
-using namespace std;
 
 int SIGDIGITS=2;
+int SIGDIGITS_ERR=1;
 
 int main(int argc, char **argv) {
   events = -1;
@@ -30,7 +30,8 @@ int main(int argc, char **argv) {
       ("events,e", po::value<int>(&events)->default_value(-1), "The number of events to run over. Set to -1 to use all events")
       ("ntower,n", po::value<int>(&ntower)->default_value(MAXTOWER), "The number of towers")
       ("files", po::value<std::vector<std::string> >(&files)->multitoken(), "FTK NTUP files")
-      ("sigdigits,s", po::value<int>(&SIGDIGITS)->default_value(2), "The number of significant digits");
+      ("sigdigits,s", po::value<int>(&SIGDIGITS)->default_value(2), "The number of significant digits")
+      ("uncertainty,u", po::value<bool>(&uncertainty)->default_value(false), "The switch to turn on/off stat uncertainties");
 
     po::variables_map vm;
     try
@@ -93,7 +94,7 @@ int main(int argc, char **argv) {
                       // disable this tower
                       if(processed[itower]>=nloop) {
                          activeTower[itower]=false;
-			 processedTower.at(itower)=true;
+			                   processedTower.at(itower)=true;
                       }
                    }
                 }
@@ -144,19 +145,19 @@ void Init() {
   myfileTeX.open (outputTeX);
   std::cout.precision (1) ;
 
-  myfileTeX << "\\documentclass[12pt]{article}" << std::endl;
-  myfileTeX << "\\usepackage[margin=1in]{geometry}" << std::endl;
+  myfileTeX << "\\documentclass[11pt]{article}" << std::endl;
+  myfileTeX << "\\usepackage[margin=0.5in]{geometry}" << std::endl;
   myfileTeX << "\\usepackage{graphicx}" << std::endl;
   myfileTeX << "\\usepackage{multirow}" << std::endl;
   myfileTeX << "\\usepackage{multicol}" << std::endl;
   myfileTeX << "\\begin{document}" << std::endl;
   myfileTeX << "\\begin{table}" << std::endl;
   myfileTeX << "\\centering" << std::endl;
-  myfileTeX << "\\begin{tabular}{|c|c|c|c|c|}" << std::endl;
+  myfileTeX << "\\begin{tabular}{|c|c|c|c|c|c|c|}" << std::endl;
   myfileTeX << "\\hline" << std::endl;
-  myfileTeX << "& \\multicolumn{2}{|c|}{Barrel} & \\multicolumn{2}{|c|}{Endcap} \\\\" << std::endl;
+  myfileTeX << "& Board & \\multicolumn{2}{|c|}{Barrel} & \\multicolumn{2}{|c|}{Endcap} & Hardware Limits \\\\" << std::endl;
   myfileTeX << "\\hline" << std::endl;
-  myfileTeX << "& Average & Max Tower & Average & Max Tower\\\\ " << std::endl;
+  myfileTeX << "& & Average & Max Tower & Average & Max Tower & \\\\ " << std::endl;
   myfileTeX << "\\hline" << std::endl;
 
   myfile << description << endl;
@@ -368,7 +369,7 @@ void Process(unsigned int ientry) {
       for (int il = 0; il < 8; il++) {
          nCluster[il][itower] += stream[itower]->naoGetNclus(il)*divide;
          nCluster_road[il][itower] += stream[itower]->naoGetNclus_road(il)*divide;
-         //SSID[il][itower] += stream[itower]->naoGetNss(il)*divide;
+         nSSID[il][itower] += stream[itower]->naoGetNss(il)*divide;
       }
    ADD_TO_HIST( stream[itower]->naoGetNclus(0),"nCluster0");
    ADD_TO_HIST( stream[itower]->naoGetNclus(1),"nCluster1");
@@ -405,44 +406,48 @@ void Process(unsigned int ientry) {
 }
 
 void Terminate() {
-  myfile << "Type\t\tbarrelmean\t\tbarrelmax\t\tendcapmean\t\tendcapmax" << endl;
-  myfile << "--------------" << endl;
+  myfile << "Type\t\tBoard\t\tBarrel Mean\t\tBarrel Max\t\tEndcap Mean\t\tEndcap Max\t\tHardware Limits" << endl;
+  myfile << "------------------------------------------" << endl;
   // kludge, can do this better but works for now
-  float temp[MAXTOWER], temp2[MAXTOWER], temp3[MAXTOWER];
+  float temp[MAXTOWER], temp2[MAXTOWER]; //, temp3[MAXTOWER];
   for (int i = 0; i < 8; i++) {
     for (int j = 0; j < MAXTOWER; j++) {
       temp[j] = nCluster[i][j];
-      temp3[j] = nCluster_road[i][j];
+      //      temp3[j] = nCluster_road[i][j];
       temp2[j] = nSSID[i][j];
     }
-    printinfo (temp, Form("NClusterL%d",i));
-    printinfo (temp3, Form("NCluster(road)L%d",i));
-    printinfo (temp2, Form("NSSIDL%d",i));
+    printinfo (temp, Form("NClusterL%d",i), "", 0);
+    // printinfo (temp3, Form("NCluster(road)L%d",i));
+    printinfo (temp2, Form("NSSIDL%d",i), "", 0);
   }
   AddBreak();
-  printinfo (nRoad, "NRoads");
+  printinfo (nRoad, "NRoads", "AUX", 4000);
+  printinfo (nFitI, "NFitAux (8/8)", "AUX", 90000);
+  printinfo (nFitRecoveryI, "NFitAux Recovery", "AUX", 700000);
+  printinfo (nTrackI, "NTrackAux", "AUX", 15000);
+  printinfo (nFitMajorityI, "NFitAux Majority", "AUX", 530000);
+  printinfo (nFitMajoritySCTI, "NFitAux Majority missing SCT", "AUX", 175000);
+  printinfo (nFitMajorityPixI, "NFitAux Majority missing Pix", "AUX", 350000);
   AddBreak();
-  printinfo (nFitI, "NFitAux (8/8 + 7/8)");
-  printinfo (nFitRecoveryI, "NFitAux Recovery");
-  printinfo (nTrackI, "NTrackAux");
-  AddBreak();
-  printinfo (nFitMajorityI, "NFitAux Majority");
-  printinfo (nFitMajoritySCTI, "NFitAux Majority missing SCT");
-  printinfo (nFitMajorityPixI, "NFitAux Majority missing Pix");
-  AddBreak();
-  printinfo (nFit, "NFitSSB (12/12 + Recovery)");
-  printinfo (nFitRecovery, "NFitSSB Recovery");
-  printinfo (nTrack, "NTrackSSB");
-  printinfo (nTrackBeforeHW, "NTrackSSB Before HW");
-  printinfo (nConn, "N Total Connections");
-  printinfo (nExtrapAUX, "N successful extrapolated AUX tracks");
-  AddBreak();
-  printinfo (nFitMajority, "NFitSSB Majority");
-  printinfo (nFitMajoritySCT, "NFitSSB Majority missing SCT");
-  printinfo (nFitMajorityPix, "NFitSSB Majority missing Pix");
+  printinfo (nFit, "NFitSSB Nominal", "SSB", 250);
+  printinfo (nFitRecovery, "NFitSSB Recovery", "SSB", 1000);
+  printinfo (nTrackBeforeHW, "NTrackSSB Before Hit Warrior", "SSB", 120);
+  printinfo (nTrack, "NTrackSSB After Hit Warrior", "SSB", 9);
+  printinfo (nConn, "N Total Connections", "SSB", 500);
+  printinfo (nExtrapAUX, "N successful extrapolated AUX tracks", "SSB", 250);
+  printinfo (nFitMajority, "NFitSSB Majority", "SSB", 500);
+  printinfo (nFitMajoritySCT, "NFitSSB Majority missing SCT", "SSB", 250);
+  printinfo (nFitMajorityPix, "NFitSSB Majority missing Pix", "SSB", 250);
+
+  myfileTeX << "\\hline" << std::endl;
+  myfileTeX << "\\end{tabular} " << std::endl;
+  myfileTeX << "\\caption{Data flow for " << nloop << " events, using " << ntower << " towers. " << description << "} " << std::endl;
+  myfileTeX << "\\end{table}" << std::endl;
+  myfileTeX << "\\end{document}" << std::endl;
+  myfileTeX.close();
 
   for (int itower = 0; itower < ntower; itower++) {
-     if(!processedTower[itower]) continue;
+     // if(!processedTower[itower]) continue; // This line causes the crash of the program.
      int first_decile_nRoad=0;
      int last_decile_nRoad=0;
      int first_decile_pos_nRoad=nRoad_tow_evt[itower].size()/10;
@@ -475,12 +480,12 @@ void Terminate() {
                     nFitI_tow_evt[itower].end());
         last_decile_nFitI=(*nth);
      }
-     AddBreak();
-     AddBreak();
+     AddBreak(2);
+
      myfile << " nRoad first decile position is " << first_decile_pos_nRoad
             << " for a value of " << first_decile_nRoad << endl;
 
-     myfile << "nRoad  last decile position is " << last_decile_pos_nRoad
+     myfile << " nRoad last decile position is " << last_decile_pos_nRoad
             << " for a value of " << last_decile_nRoad << endl;  
     
      myfile << " nFitI first decile position is " << first_decile_pos_nFitI
@@ -499,13 +504,6 @@ void Terminate() {
    //myfile << " first decile position is cool " << endl;
 
   myfile.close();
-
-  myfileTeX << "\\hline" << std::endl;
-  myfileTeX << "\\end{tabular} " << std::endl;
-  myfileTeX << "\\caption{Data flow for " << nloop << " events, using " << ntower << " towers. " << description << "} " << std::endl;
-  myfileTeX << "\\end{table}" << std::endl;
-  myfileTeX << "\\end{document}" << std::endl;
-  myfileTeX.close();
    
   outputHistFirstDecile->GetYaxis()->SetBinLabel(1,"nRoad");
   outputHistLastDecile->GetYaxis()->SetBinLabel(1,"nRoad");
@@ -531,12 +529,14 @@ double roundTo(double x,int precision) {
    return x;
 }
 
-void printinfo(float towers[MAXTOWER], TString text) {
+void printinfo(float towers[MAXTOWER], TString quantity_name, TString board, float HW_limit) {
 
    int barrelN=0,endcapN=0;
-  float barrelmean(0), endcapmean(0), barrelmax(0), endcapmax(0);
+  float barrelmean(0), endcapmean(0), barrelmax(0), endcapmax(0), hw_limit(HW_limit);
+  float barrelmean_err(0), endcapmean_err(0), barrelmax_err(0), endcapmax_err(0);
+
   for (int i = 0; i<ntower; i++) {
-     if(!processedTower[i]) continue;
+     // if(!processedTower[i]) continue; // This line causes the crash of the program.
     if (i < (ntower/4) || i >= 3*(ntower/4.)) { // kludge not always (?) guaranteed to work
       if (towers[i] > endcapmax) endcapmax = towers[i];
       endcapmean += towers[i];
@@ -555,9 +555,63 @@ void printinfo(float towers[MAXTOWER], TString text) {
   barrelmax = roundTo(barrelmax,SIGDIGITS);
   endcapmean = roundTo(endcapmean,SIGDIGITS);
   endcapmax = roundTo(endcapmax,SIGDIGITS);
+  
+  if (uncertainty) {
+  	barrelmean_err = sqrt(barrelmean/nloop/ntower);
+    barrelmax_err = sqrt(barrelmax/nloop/ntower);
+    endcapmean_err = sqrt(endcapmean/nloop/ntower);
+    endcapmax_err = sqrt(endcapmax/nloop/ntower);
 
-  myfile << text << "\t\t" << barrelmean << "\t\t" << barrelmax << "\t\t" << endcapmean << "\t\t" << endcapmax << endl;
-  myfileTeX << text << "&" << barrelmean << "&" << barrelmax << "&" << endcapmean << "&" << endcapmax << " \\\\" << endl;
+  	barrelmean_err = roundTo(barrelmean_err,SIGDIGITS_ERR);
+	barrelmax_err = roundTo(barrelmax_err,SIGDIGITS_ERR);
+	endcapmean_err = roundTo(endcapmean_err,SIGDIGITS_ERR);
+	endcapmax_err = roundTo(endcapmax_err,SIGDIGITS_ERR);
+
+	myfile << quantity_name << "\t\t" << board << "\t\t";
+  	myfile << barrelmean << "±" << barrelmean_err << "\t\t";
+  	myfile << barrelmax << "±" << barrelmax_err << "\t\t";
+  	myfile << endcapmean << "±" << endcapmean_err << "\t\t";
+  	myfile << endcapmax << "±" << endcapmax_err << "\t\t";
+
+    myfileTeX << quantity_name << "&" << board << "&";
+
+    if ((barrelmean > hw_limit) && (hw_limit != 0)) myfileTeX << "\\textbf{" << barrelmean << "$\\pm$" << barrelmean_err << "}" << "&";
+    else myfileTeX << barrelmean << "$\\pm$" << barrelmean_err << "&";
+
+	myfileTeX << barrelmax << "$\\pm$" << barrelmax_err << "&";
+
+    if ((endcapmean > hw_limit) && (hw_limit != 0)) myfileTeX << "\\textbf{" << endcapmean << "$\\pm$" << endcapmean_err << "}" << "&";
+    else myfileTeX << endcapmean << "$\\pm$" << endcapmean_err << "&";
+
+	myfileTeX << endcapmax << "$\\pm$" << endcapmax_err << "&";
+
+  }
+
+  else {
+  	myfile << quantity_name << "\t\t" << board << "\t\t";
+    myfile << barrelmean << "\t\t" << barrelmax << "\t\t" << endcapmean << "\t\t" << endcapmax << "\t\t";
+
+    myfileTeX << quantity_name << "&" << board << "&";
+
+    if ((barrelmean > hw_limit) && (hw_limit != 0)) myfileTeX << "\\textbf{" << barrelmean << "}" << "&";
+    else myfileTeX << barrelmean << "&";
+
+    myfileTeX << barrelmax << "&";
+
+    if ((endcapmean > hw_limit) && (hw_limit != 0)) myfileTeX << "\\textbf{" << endcapmean << "}" << "&";
+    else myfileTeX << endcapmean << "&";
+
+    myfileTeX << endcapmax << "&";
+  }
+
+  if (hw_limit == 0) {
+  	myfile << endl;
+  	myfileTeX << " \\\\" << endl;
+  }
+  else {
+  	myfile << hw_limit << endl;
+  	myfileTeX << hw_limit << " \\\\" << endl;
+  }
 }
 
 void AddBreak(int n) {
@@ -566,4 +620,3 @@ void AddBreak(int n) {
     myfileTeX << "\\hline" << std::endl;
   }
 }
-
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.h b/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.h
index 81229ee7ba61..a99293950715 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.h
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/dataflow.h
@@ -12,7 +12,6 @@
 
 #define MAXTOWER 64
 #define MAXL 8
-
 ///#define HIST_MAXBINS 35
 
 #define HIST_MAXBINS 100
@@ -20,9 +19,10 @@
 
 #define TTREE_NAME "ftkdata"
 
+using namespace std;
 
-std::ofstream myfile;
-std::ofstream myfileTeX;
+ofstream myfile;
+ofstream myfileTeX;
 
 // [tower]
 float nRoad[MAXTOWER], nFit[MAXTOWER], nFitI[MAXTOWER], nTrack[MAXTOWER], nTrackI[MAXTOWER], nTrackBeforeHW[MAXTOWER], nFitRecovery[MAXTOWER], nFitRecoveryI[MAXTOWER];
@@ -32,7 +32,7 @@ float nConn[MAXTOWER], nExtrapAUX[MAXTOWER];
 FTKRoadStream *stream[MAXTOWER];
 FTKTrackStream *trackstream[MAXTOWER];
 
-std::vector<float> nRoad_tow_evt[MAXTOWER], nFitI_tow_evt[MAXTOWER];
+vector<float> nRoad_tow_evt[MAXTOWER], nFitI_tow_evt[MAXTOWER];
 
 
 // events to run over
@@ -66,9 +66,12 @@ std::vector<std::string> files;
 TChain *ch;
 std::vector<std::pair<size_t,std::vector<bool> > > towersPerFile;
 
+// The switch to turn on/off stat uncertainties
+bool uncertainty;
+
 
 void Init();
 void Process(unsigned int ientry);
 void Terminate();
-void printinfo(float towers[MAXTOWER], TString text);
+void printinfo(float towers[MAXTOWER], TString quantity_name, TString board, float HW_limit);
 void AddBreak(int n = 1);
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.cc
index bac3a623e0a5..9e4156f92129 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.cc
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.cc
@@ -14,7 +14,6 @@
 #include "boost/filesystem.hpp"
 
 #include <vector>
-using namespace std;
 
 void printpsfile(std::string, TFile* f);
 
@@ -73,6 +72,14 @@ void Init() {
   // create instances for the FTK generic distributions
   histocoordmasketa_ftk = new TH2F("histocoordmasketa_ftk","Track probability of using a coordinate;Coordinate bit;#eta;Prob.",16,0,16,nbins,etamin,etamax);
   histocoordmaskphi_ftk = new TH2F("histocoordmaskphi_ftk","Track probability of using a coordinate;Coordinate bit;#phi;Prob.",16,0,16,nbins,phimin,phimax);
+  for(int i=0;i<=16;i++) {
+     histocoordmasketaphi_ftk[i] = new TH2F
+        (TString::Format("histocoordmasketaphiL%d_ftk",i),"Track probability of using a coordinate;#eta;#phi;Prob.",32,etamin,etamax,32,phimin,phimax);
+     histoeff_etaphiplane[i]= new TH2F
+        (TString::Format("histoeff_etaphiL%d",i),
+         TString::Format("efficiency plane %d;#eta;#phi;Prob.",i),
+         32,etamin,etamax,32,phimin,phimax);
+  }
   histocoordmaskz0_ftk = new TH2F("histocoordmaskz0_ftk","Track probability of using a coordinate;Coordinate bit;#z0;Prob.",16,0,16,nbins,z0min, z0max);
   histonmisseta_ftk = new TH2F("histonmisseta_ftk","Track probability of missing N layers;N Miss;#eta;Prob.",6,0,6,nbins,etamin,etamax);
   histochisqndfeta_ftk = new TH2F("histochisqndfeta_ftk","Track probability of #chi^{2};#chi^{2}/ndf;#eta;Prob.",20,0,20,nbins,etamin,etamax);
@@ -178,6 +185,12 @@ void Init() {
   histod0res_veta = new TProfile("histod0res_veta","#Delta d_{0} (mm);#eta", nbins, etamin, etamax);
   histoz0res_veta = new TProfile("histoz0res_veta","#Delta z_{0} (mm);eta", nbins, etamin, etamax);
   histod0res_vphi = new TProfile("histod0res_vphi","#Delta d_{0} (mm);#phi", nbins, phimin, phimax);
+  histo2d0res_vphi = new TH2F("histo2d0res_vphi","#Delta d_{0} (mm);#phi", nbins, phimin, phimax,50,-5.*Dd0,5.*Dd0);
+  histo2d0res_veta = new TH2F("histo2d0res_veta","#Delta d_{0} (mm);#eta", nbins, etamin, etamax,50,-5.*Dd0,5.*Dd0);
+  histo2d0res_coordbit = new TH2F("histo2d0res_coordbit","#Delta d_{0} (mm);coordinate bit", 16, -0.5, 15.5,50,-5.*Dd0,5.*Dd0);
+  histo2d0truth_vphi = new TH2F("histo2d0truth_vphi",";#phi;truth d_{0} (mm)", nbins, phimin, phimax,50,-4.,4.);
+  histo2d0ftk_vphi = new TH2F("histo2d0ftk_vphi",";#phi;FTK d_{0} (mm)", nbins, phimin, phimax,50,-4.,4.);
+  histo2curvCurv = new TH2F("histo2curvCurv",";curv;curv",50,-abscurvmax ,abscurvmax ,50,-abscurvmax,abscurvmax);
   histoz0res_vphi = new TProfile("histoz0res_vphi","#Delta z_{0} (mm);#phi", nbins, phimin, phimax);
   histod0res_vz0 = new TProfile("histod0res_vz0","#Delta d_{0} (mm);z_{0} (mm)", nbins, z0min, z0max);
   histoz0res_vz0 = new TProfile("histoz0res_vz0","#Delta z_{0} (mm);z_{0} (mm)", nbins, z0min, z0max);
@@ -264,20 +277,15 @@ void Process(Long64_t ientry) {
       curtrack = (Use1stStage ? tracks->getTrackI(itrk) : tracks->getTrack(itrk));
       //if (  TMath::Abs(curtrack->getPt())*1e-3 < ptmincut ) continue;
       
+      
+      //double temp_phi = curtrack->getPhi();
+      //double temp_d0 = curtrack->getIP();
+      //double temp_z0 = curtrack->getZ0();
 
-      double temp_phi = curtrack->getPhi();
-      double temp_d0 = curtrack->getIP();
-      double temp_z0 = curtrack->getZ0();
-
-      // double dx = -0.42;
-      // double dy = -0.53;
-
-
-      // double dx = -0.5491;
-      // double dy = -0.6557;
-
-      double thisd0 = temp_d0 + dx*sin(temp_phi)-dy*cos(temp_phi);
-      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+      double thisd0 = curtrack->getIP();
+      //temp_d0 + dx*sin(temp_phi)-dy*cos(temp_phi);
+      double thisz0 = curtrack->getZ0();
+      //temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
 
       histod0_ftk->Fill(thisd0);
 
@@ -356,10 +364,14 @@ void Process(Long64_t ientry) {
       if (curtrack->getBitmask()&(1<<6)) histophiz0_ftk_PixL2->Fill(curtrack->getPhi(),thisz0);
       
       
+      histocoordmasketaphi_ftk[16]
+         ->Fill(curtrack->getEta(),curtrack->getPhi());
       for (Int_t icoord=0;icoord!=curtrack->getNCoords();++icoord) {
 
 	if (curtrack->getBitmask()&(1<<icoord)){
 	  histocoordmasketa_ftk->Fill(icoord,curtrack->getEta());
+	  histocoordmasketaphi_ftk[icoord]
+             ->Fill(curtrack->getEta(),curtrack->getPhi());
 	  histocoordmaskz0_ftk->Fill(icoord,thisz0);
 	  histocoordmaskphi_ftk->Fill(icoord,curtrack->getPhi());
 	  // std::cout << "icoord, eta, z0, phi: " << icoord << ", " << curtrack->getEta() << ", " << thisz0 << ", " << curtrack->getPhi() << std::endl;
@@ -437,6 +449,7 @@ void Process(Long64_t ientry) {
       FTKRoad *road = roads->getRoad(iroad);
       for( int i=0; i < road->getNPlanes(); ++i ) {
 	const std::vector<FTKHit>& hits = road->getHits(i);
+	//	std::vector<FTKHit>::const_iterator match_hit=hits.end();
 	for( std::vector<FTKHit>::const_iterator ihit=hits.begin(), fhit=hits.end(); ihit!=fhit; ++ihit ) {
 	  //	  const FTKHit& hit = *ihit;
 	  // printf("plane = %d\n", hit.getPlane());
@@ -482,9 +495,10 @@ void Process(Long64_t ientry) {
   vector<FTKTruthTrack>::const_iterator itr = truthTracks->begin();
   vector<FTKTruthTrack>::const_iterator itrE = truthTracks->end();
   for (;itr!=itrE;++itr) { // loop over the truth tracks
-    const FTKTruthTrack &curtruth = (*itr);
+    const FTKTruthTrack &curtruth_fromFile = (*itr);
+    // apply vertex shift
 
-    int barcode = curtruth.getBarcode();
+    int barcode = curtruth_fromFile.getBarcode();
     if (barcode>100000 || barcode==0) continue;
 
     // select only good truth tracks
@@ -492,88 +506,92 @@ void Process(Long64_t ientry) {
     // double dy = curtruth.getY();
     // double d0 = -1e-3*(dx*py-dy*px)*invpt;
 
-    double px = curtruth.getPX();
-    double py = curtruth.getPY();
-    double pt = 1e-3*TMath::Sqrt(px*px+py*py);
-    double invpt = 1./pt;
-
-    if ( pt < ptmincut ) continue;
-
-    double d0 = curtruth.getD0();
-    if (d0<d0min || d0>d0max) continue;
-
-    double z0 = curtruth.getZ();
-    if (z0<z0min || z0>z0max) continue;
+    double px_truth = curtruth_fromFile.getPX();
+    double py_truth = curtruth_fromFile.getPY();
+    double pt_truth = 1e-3*TMath::Hypot(px_truth,py_truth);
+    double invpt_truth = 1./pt_truth;
+    double d0_truth = curtruth_fromFile.getD0();
+    double z0_truth = curtruth_fromFile.getZ();
+    double curv_truth = .5*curtruth_fromFile.getQ()*invpt_truth;
+    double phi_truth = curtruth_fromFile.getPhi();
+    double eta_truth = curtruth_fromFile.getEta();
+    double cotTheta_truth= pt_truth/curtruth_fromFile.getPZ();
+    int pdgcode = curtruth_fromFile.getPDGCode();
+    int eventIndex_truth=curtruth_fromFile.getEventIndex();
+
+    if (d0_truth<d0min || d0_truth>d0max) continue;
+    if (z0_truth<z0min || z0_truth>z0max) continue;
+
+    if ( pt_truth < ptmincut ) continue;
+    if (curv_truth<-abscurvmax || curv_truth>abscurvmax) continue;
+    if (phi_truth<phimin || phi_truth>phimax) continue;
+    if (eta_truth<etamin || eta_truth>etamax) continue;
+    if (eventIndex_truth!=0 && curtruth_fromFile.getQ()==0) continue;
+
+    // transform variables to shifted vertex
+    // only d0,z0 is corrected here (lowest order corrections)
+    d0_truth -= vtxTruth[0]*sin(phi_truth)-vtxTruth[1]*cos(phi_truth);
+    z0_truth -= vtxTruth[2]+((cos(phi_truth) *vtxTruth[0] - sin(phi_truth)*vtxTruth[1]))*cotTheta_truth;
 
-    double curv = .5*curtruth.getQ()*invpt;
-    if (curv<-abscurvmax || curv>abscurvmax) continue;
-
-    double phi = curtruth.getPhi();
-    if (phi<phimin || phi>phimax) continue;
-
-    double eta = curtruth.getEta();
-    if (eta<etamin || eta>etamax) continue;
-
-    if (curtruth.getEventIndex()!=0 && curtruth.getQ()==0) continue;
 
     ntruth_good += 1;
 
     // Fill the histogram for the generic truth distribution
-    histod0_truth->Fill(d0);
-    histoz0_truth->Fill(z0);
-    histocurv_truth->Fill(curv);
-    histophi_truth->Fill(curtruth.getPhi());
-    histoetaphi_truth->Fill(eta, curtruth.getPhi());
-    histoetaz0_truth->Fill(eta, z0);
-    histoeta_truth->Fill(eta);
-    histoetaabs_truth->Fill(fabs(eta));
+    histod0_truth->Fill(d0_truth);
+    histoz0_truth->Fill(z0_truth);
+    histocurv_truth->Fill(curv_truth);
+    histophi_truth->Fill(phi_truth);
+    histoetaphi_truth->Fill(eta_truth, phi_truth);
+    histoetaz0_truth->Fill(eta_truth, z0_truth);
+    histoeta_truth->Fill(eta_truth);
+    histoetaabs_truth->Fill(fabs(eta_truth));
     histoeff_truth->Fill(0);
-    histopt_truth->Fill(pt);
-    histopt_truth_lg->Fill(pt);
-    histopt_truthlo_lg->Fill(pt);
+    histopt_truth->Fill(pt_truth);
+    histopt_truth_lg->Fill(pt_truth);
+    histopt_truthlo_lg->Fill(pt_truth);
 
-    int pdgcode = curtruth.getPDGCode();
     if (pdgcode==13 || pdgcode==-13) {
       // muon block
       ntruth_good_muon += 1;
 
-      histod0_truth_muon->Fill(d0);
-      histoz0_truth_muon->Fill(z0);
-      histocurv_truth_muon->Fill(curv);
-      histophi_truth_muon->Fill(curtruth.getPhi());
-      histoeta_truth_muon->Fill(eta);
-      histopt_truth_muon->Fill(pt);
-      histopt_truth_muon_lg->Fill(pt);
-      histopt_truth_muonlo_lg->Fill(pt);
+      histod0_truth_muon->Fill(d0_truth);
+      histoz0_truth_muon->Fill(z0_truth);
+      histocurv_truth_muon->Fill(curv_truth);
+      histophi_truth_muon->Fill(phi_truth);
+      histoeta_truth_muon->Fill(eta_truth);
+      histopt_truth_muon->Fill(pt_truth);
+      histopt_truth_muon_lg->Fill(pt_truth);
+      histopt_truth_muonlo_lg->Fill(pt_truth);
     }
 
     // match the barcode and event index values
-    MatchInfo reftruth(barcode,curtruth.getEventIndex());
+    MatchInfo reftruth(barcode,eventIndex_truth);
     pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrange = ftkmatchinfo.equal_range(reftruth);
+    int bitmask=0;
     if (mrange.first != mrange.second) {
-      histod0_truthM->Fill(d0);
-      histoz0_truthM->Fill(z0);
-      histocurv_truthM->Fill(curv);
-      histophi_truthM->Fill(curtruth.getPhi());
-      histoetaphi_truthM->Fill(eta, curtruth.getPhi());
-      histoetaz0_truthM->Fill(eta, z0);
-      histoeta_truthM->Fill(eta);
-      histoetaabs_truthM->Fill(fabs(eta));
+      histod0_truthM->Fill(d0_truth);
+      histoz0_truthM->Fill(z0_truth);
+      histocurv_truthM->Fill(curv_truth);
+      histophi_truthM->Fill(phi_truth);
+      histoetaphi_truthM->Fill(eta_truth, phi_truth);
+      histoetaz0_truthM->Fill(eta_truth, z0_truth);
+      histoeta_truthM->Fill(eta_truth);
+      histoetaabs_truthM->Fill(fabs(eta_truth));
       histoeff_truthM->Fill(0);
-      histopt_truthM->Fill(pt);
-      histopt_truthMlo_lg->Fill(pt);
-      histopt_truthM_lg->Fill(pt);
+      histopt_truthM->Fill(pt_truth);
+      histopt_truthMlo_lg->Fill(pt_truth);
+      histopt_truthM_lg->Fill(pt_truth);
 
       if (pdgcode==13 || pdgcode==-13) {
         // matched muon block
-        histod0_truthM_muon->Fill(d0);
-        histoz0_truthM_muon->Fill(z0);
-        histocurv_truthM_muon->Fill(curv);
-        histophi_truthM_muon->Fill(curtruth.getPhi());
-        histoeta_truthM_muon->Fill(eta);
-        histopt_truthM_muon->Fill(pt);
-        histopt_truthM_muon_lg->Fill(pt);
-        histopt_truthM_muonlo_lg->Fill(pt);
+        histod0_truthM_muon->Fill(d0_truth);
+        histoz0_truthM_muon->Fill(z0_truth);
+        histocurv_truthM_muon->Fill(curv_truth);
+        histophi_truthM_muon->Fill(phi_truth);
+        histoeta_truthM_muon->Fill(eta_truth);
+        histopt_truthM_muon->Fill(pt_truth);
+        histopt_truthM_muon_lg->Fill(pt_truth);
+        histopt_truthM_muonlo_lg->Fill(pt_truth);
       }
 
       const FTKTrack *bestftk(0x0);
@@ -586,22 +604,43 @@ void Process(Long64_t ientry) {
       }
       
       if (bestftk) {
-	histod0res->Fill(d0-bestftk->getIP());
-	histoz0res->Fill(z0-bestftk->getZ0());
-	histod0res_veta->Fill(eta,d0-bestftk->getIP());
-	histoz0res_veta->Fill(eta,z0-bestftk->getZ0());
-	histod0res_vphi->Fill(curtruth.getPhi(),d0-bestftk->getIP());
-	histoz0res_vphi->Fill(curtruth.getPhi(),z0-bestftk->getZ0());
-	histod0res_vz0->Fill(z0,d0-bestftk->getIP());
-	histoz0res_vz0->Fill(z0,z0-bestftk->getZ0());
-
-	histocurvres->Fill(curv-bestftk->getHalfInvPt()*1e3);
-	histophires->Fill(curtruth.getPhi()-bestftk->getPhi());
-	histoetares->Fill(eta-bestftk->getEta());
-	historelptres->Fill((pt-TMath::Abs(bestftk->getPt())*1e-3)*invpt);
-	historelptrespt->Fill(pt,(pt-TMath::Abs(bestftk->getPt())*1e-3)*invpt);
+	histod0res->Fill(d0_truth-bestftk->getIP());
+	histoz0res->Fill(z0_truth-bestftk->getZ0());
+	histod0res_veta->Fill(eta_truth,d0_truth-bestftk->getIP());
+	histoz0res_veta->Fill(eta_truth,z0_truth-bestftk->getZ0());
+	histod0res_vphi->Fill(phi_truth,d0_truth-bestftk->getIP());
+	histo2d0res_vphi->Fill(phi_truth,d0_truth-bestftk->getIP());
+	histo2d0res_veta->Fill(eta_truth,d0_truth-bestftk->getIP());
+	histo2d0truth_vphi->Fill(phi_truth,d0_truth);
+	histo2d0ftk_vphi->Fill(phi_truth,bestftk->getIP());
+	histo2curvCurv->Fill(curv_truth,bestftk->getHalfInvPt()*1.E3);
+	histoz0res_vphi->Fill(phi_truth,z0_truth-bestftk->getZ0());
+	histod0res_vz0->Fill(z0_truth,d0_truth-bestftk->getIP());
+	histoz0res_vz0->Fill(z0_truth,z0_truth-bestftk->getZ0());
+
+	histocurvres->Fill(curv_truth-bestftk->getHalfInvPt()*1e3);
+	histophires->Fill(phi_truth-bestftk->getPhi());
+	histoetares->Fill(eta_truth-bestftk->getEta());
+	historelptres->Fill((pt_truth-TMath::Abs(bestftk->getPt())*1e-3)*invpt_truth);
+	historelptrespt->Fill(pt_truth,(pt_truth-TMath::Abs(bestftk->getPt())*1e-3)*invpt_truth);
+        bitmask=bestftk->getBitmask();
+        for(int icoord=0;icoord<16;icoord++) {
+           if (bitmask&(1<<icoord)){
+              histo2d0res_coordbit->Fill(icoord,d0_truth-bestftk->getIP());
+           }
+        }
       }
     }
+    // fill efficiency per plane in eta,phi
+    if(mrange.first!=mrange.second) {
+       bitmask |= 1<<16;
+       for(Int_t icoord=0;icoord<=16;++icoord) {
+          if (bitmask&(1<<icoord)){
+             histoeff_etaphiplane[icoord]->Fill(eta_truth,phi_truth);
+          }
+       }
+    }
+
   } // end loop over truth tracks
 
   // fill counter histograms
@@ -719,6 +758,15 @@ void Terminate(std::string& outputname) {
 
   ofile->Add(histocoordmasketa_ftk);
   ofile->Add(histocoordmaskphi_ftk);
+  for(int i=0;i<16;i++) {
+     histocoordmasketaphi_ftk[i]->Divide(histocoordmasketaphi_ftk[16]); 
+     histoeff_etaphiplane[i]->Divide(histoeff_etaphiplane[16]); 
+  }
+
+  for(int i=0;i<16;i++) {
+     ofile->Add(histocoordmasketaphi_ftk[i]);
+     ofile->Add(histoeff_etaphiplane[i]);
+  }
   ofile->Add(histocoordmaskz0_ftk);
   ofile->Add(histonmisseta_ftk);
   ofile->Add(histochisqndfeta_ftk);
@@ -813,6 +861,12 @@ void Terminate(std::string& outputname) {
   ofile->Add(histod0res_veta);
   ofile->Add(histoz0res_veta);
   ofile->Add(histod0res_vphi);
+  ofile->Add(histo2d0res_vphi);
+  ofile->Add(histo2d0res_veta);
+  ofile->Add(histo2d0res_coordbit);
+  ofile->Add(histo2d0truth_vphi);
+  ofile->Add(histo2d0ftk_vphi);
+  ofile->Add(histo2curvCurv);
   ofile->Add(histoz0res_vphi);
   ofile->Add(histod0res_vz0);
   ofile->Add(histoz0res_vz0);
@@ -897,8 +951,11 @@ int main(int argc, char **argv) {
   std::string output;
   std::vector<std::string> files;
   ptmincut = 0;
-  dx = -0.5;
-  dy = -0.5;
+  //dx = -0.5;
+  //dy = -0.5;
+  vtxTruth[0]=0.;
+  vtxTruth[1]=0.;
+  vtxTruth[2]=0.;
 
   try {
     std::string appName = boost::filesystem::basename(argv[0]);
@@ -914,8 +971,11 @@ int main(int argc, char **argv) {
       ("use-first-stage", po::value<int>(&Use1stStage)->default_value(0), "-1: Use roads, 1: Use 1st stage tracks, 0(default): Use 2nd stage tracks")
       ("files", po::value<std::vector<std::string> >(&files)->multitoken(), "FTK NTUP files")
        ("ptmincut", po::value<double>(&ptmincut), "min pt cut on truth tracks")
-       ("dx", po::value<double>(&dx)->default_value(-0.5), "dx")
-       ("dy", po::value<double>(&dy)->default_value(-0.5), "dx")
+       //("dx", po::value<double>(&dx)->default_value(-0.5), "vertex-x for d0,z0 shift")
+       //("dy", po::value<double>(&dy)->default_value(-0.5), "vertex-y for d0,z0 shift")
+       ("vxTruth", po::value<double>(vtxTruth+0)->default_value(0.), "vertex-x shift for truth tracks")
+       ("vyTruth", po::value<double>(vtxTruth+1)->default_value(0.), "vertex-y shift for truth tracks")
+       ("vzTruth", po::value<double>(vtxTruth+2)->default_value(0.), "vertex-z shift for truth tracks")
        ("psfile", "Produce postscript file with efficieny plots");
 
     po::variables_map vm;
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.h b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.h
index dd3fba315010..149bbecaf548 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.h
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency.h
@@ -14,6 +14,7 @@
 #include "TFile.h"
 #include "TProfile.h"
 
+using namespace std;
 
 class MatchInfo {
 private:
@@ -27,7 +28,7 @@ public:
   bool operator<(const MatchInfo& o) const { if (m_evtindex!=o.m_evtindex) return (m_evtindex<o.m_evtindex); else return m_barcode<o.m_barcode; }
 };
 
-typedef std::multimap<MatchInfo,const FTKTrack*> FTKBarcodeMM;
+typedef multimap<MatchInfo,const FTKTrack*> FTKBarcodeMM;
 unsigned nbins;
 double maxntracks;
 double d0min, d0max;
@@ -43,10 +44,12 @@ double Dcurv;
 double Deta;
 double Dz0;
 double ptmincut;
-double dx, dy;
+//double dx, dy;
+double vtxTruth[3];
 
 // block of generic control histograms for the FTK tracks
 TH2F *histocoordmasketa_ftk;
+TH2F *histocoordmasketaphi_ftk[17];
 TH2F *histocoordmaskz0_ftk;
 TH2F *histocoordmaskphi_ftk;
 TH2F *histonmisseta_ftk;
@@ -68,6 +71,8 @@ TH1F *histocurv_ftk;
 TH1F *histoeta_ftk;
 TH2F *histoetaphi_ftk;
 
+TH2F *histoeff_etaphiplane[17];
+
 
 TH2F *histoetaphi_ftk_IBL;
 TH2F *histoetaphi_ftk_PixL0;
@@ -160,6 +165,12 @@ TH1F *histoz0res;
 TProfile *histod0res_veta;
 TProfile *histoz0res_veta;
 TProfile *histod0res_vphi;
+TH2F *histo2d0res_vphi;
+TH2F *histo2d0res_veta;
+TH2F *histo2d0res_coordbit;
+TH2F *histo2d0truth_vphi;
+TH2F *histo2d0ftk_vphi;
+TH2F *histo2curvCurv;
 TProfile *histoz0res_vphi;
 TProfile *histod0res_vz0;
 TProfile *histoz0res_vz0;
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.cc
new file mode 100644
index 000000000000..84d8eee4dc70
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.cc
@@ -0,0 +1,835 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "efficiency_step_by_step.h"
+#include "TChain.h"
+#include "TSystem.h"
+#include "TGraphAsymmErrors.h"
+#include "TROOT.h"
+#include "TStyle.h"
+#include "TCanvas.h"
+
+#include "boost/program_options.hpp"
+#include "boost/filesystem.hpp"
+
+#include <vector>
+
+void Init() {
+  // define the boundaries for
+  nbins = 50;
+  maxntracks = 500;
+  d0min = -2.;
+  d0max = 2.;
+  z0min = -110.;
+  z0max = 110.;
+  phimin = -TMath::Pi();
+  phimax = TMath::Pi();
+  //phimin = 2.3;
+  //phimax = 2.6;
+  abscurvmax = .5;
+  //etamin = -1.1;
+  //etamax = 0.15;
+  etamin = -2.5;
+  etamax = 2.5;
+  ptmax = 100;
+  Dd0 = 0.2;
+  Drelpt = 1.;
+  Dcurv = .05;
+  Dphi = .01;
+  Dz0 = 1.5;
+  Deta = .02;
+
+
+  // Int_t nptbins = 24;
+  // Double_t ptbins[] = {0,1,2,3,4,5,6,8,10,12,14,16,18,20,25,30,35,40,45,50,60,70,80,90,100};
+  // TDR binning
+  Int_t nptbins = 21;
+  Double_t ptbins[] = {0,2,4,6,8,10,12,14,16,18,20,25,30,35,40,45,50,60,70,80,90,100};
+
+  // create instances for the FTK generic distributions
+
+  histopt_ftk = new TH1F("histopt_ftk",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_ftk = new TH1F("histoeta_ftk",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_ftk = new TH1F("histophi_ftk",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_ftk_pre_hw = new TH1F("histopt_ftk_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_ftk_pre_hw = new TH1F("histoeta_ftk_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_ftk_pre_hw = new TH1F("histophi_ftk_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_ftkI = new TH1F("histopt_ftkI",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_ftkI = new TH1F("histoeta_ftkI",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_ftkI = new TH1F("histophi_ftkI",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_ftkI_pre_hw = new TH1F("histopt_ftkI_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_ftkI_pre_hw = new TH1F("histoeta_ftkI_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_ftkI_pre_hw = new TH1F("histophi_ftkI_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_ftk_pattern = new TH1F("histopt_ftk_pattern",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_ftk_pattern = new TH1F("histoeta_ftk_pattern",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_ftk_pattern = new TH1F("histophi_ftk_pattern",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_ftk_hits = new TH1F("histopt_ftk_hits",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_ftk_hits = new TH1F("histoeta_ftk_hits",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_ftk_hits = new TH1F("histophi_ftk_hits",";#phi;N Tracks",nbins,phimin,phimax);
+
+  // create instances for the fakes distribtuions
+
+  histopt_goodftk = new TH1F("histopt_goodftk",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftk = new TH1F("histoeta_goodftk",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftk = new TH1F("histophi_goodftk",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftk_pre_hw = new TH1F("histopt_goodftk_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftk_pre_hw = new TH1F("histoeta_goodftk_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftk_pre_hw = new TH1F("histophi_goodftk_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkI = new TH1F("histopt_goodftkI",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkI = new TH1F("histoeta_goodftkI",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkI = new TH1F("histophi_goodftkI",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkI_pre_hw = new TH1F("histopt_goodftkI_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkI_pre_hw = new TH1F("histoeta_goodftkI_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkI_pre_hw = new TH1F("histophi_goodftkI_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftk_pattern = new TH1F("histopt_goodftk_pattern",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftk_pattern = new TH1F("histoeta_goodftk_pattern",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftk_pattern = new TH1F("histophi_goodftk_pattern",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftk_hits = new TH1F("histopt_goodftk_hits",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftk_hits = new TH1F("histoeta_goodftk_hits",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftk_hits = new TH1F("histophi_goodftk_hits",";#phi;N Tracks",nbins,phimin,phimax);
+
+
+  histopt_goodftkU = new TH1F("histopt_goodftkU",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkU = new TH1F("histoeta_goodftkU",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkU = new TH1F("histophi_goodftkU",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkU_pre_hw = new TH1F("histopt_goodftkU_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkU_pre_hw = new TH1F("histoeta_goodftkU_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkU_pre_hw = new TH1F("histophi_goodftkU_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkUI = new TH1F("histopt_goodftkUI",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkUI = new TH1F("histoeta_goodftkUI",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkUI = new TH1F("histophi_goodftkUI",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkUI_pre_hw = new TH1F("histopt_goodftkUI_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkUI_pre_hw = new TH1F("histoeta_goodftkUI_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkUI_pre_hw = new TH1F("histophi_goodftkUI_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkU_pattern = new TH1F("histopt_goodftkU_pattern",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkU_pattern = new TH1F("histoeta_goodftkU_pattern",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkU_pattern = new TH1F("histophi_goodftkU_pattern",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_goodftkU_hits = new TH1F("histopt_goodftkU_hits",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_goodftkU_hits = new TH1F("histoeta_goodftkU_hits",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_goodftkU_hits = new TH1F("histophi_goodftkU_hits",";#phi;N Tracks",nbins,phimin,phimax);
+
+  // create instances for the truth and efficiency distributions
+
+  histopt_truth = new TH1F("histopt_truth",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truth = new TH1F("histoeta_truth",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truth = new TH1F("histophi_truth",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthM = new TH1F("histopt_truthM",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthM = new TH1F("histoeta_truthM",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthM = new TH1F("histophi_truthM",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthM_pre_hw = new TH1F("histopt_truthM_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthM_pre_hw = new TH1F("histoeta_truthM_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthM_pre_hw = new TH1F("histophi_truthM_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthMI = new TH1F("histopt_truthMI",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthMI = new TH1F("histoeta_truthMI",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthMI = new TH1F("histophi_truthMI",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthMI_pre_hw = new TH1F("histopt_truthMI_pre_hw",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthMI_pre_hw = new TH1F("histoeta_truthMI_pre_hw",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthMI_pre_hw = new TH1F("histophi_truthMI_pre_hw",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthM_pattern = new TH1F("histopt_truthM_pattern",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthM_pattern = new TH1F("histoeta_truthM_pattern",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthM_pattern = new TH1F("histophi_truthM_pattern",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthM_hits = new TH1F("histopt_truthM_hits",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthM_hits = new TH1F("histoeta_truthM_hits",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthM_hits = new TH1F("histophi_truthM_hits",";#phi;N Tracks",nbins,phimin,phimax);
+
+  histopt_truthM_cond = new TH1F("histopt_truthM_cond",";p_{T} (GeV);N Tracks",nptbins,ptbins);
+  histoeta_truthM_cond = new TH1F("histoeta_truthM_cond",";#eta;N Tracks",nbins,etamin,etamax);
+  histophi_truthM_cond = new TH1F("histophi_truthM_cond",";#phi;N Tracks",nbins,phimin,phimax);
+
+  ientry2=0;
+}
+
+
+void Process(Long64_t ientry) {
+
+  t_ftkdata->GetEntry(ientry);
+
+  // collect information from the run-evt from the truth
+  Int_t evtnumber_ftk = tracks->eventNumber();
+  Int_t runnumber_ftk = tracks->runNumber();
+
+  if (ientry%10==0) {
+    Info("Process","Event %lld, (Run,Evt) = (%d,%d)",ientry, runnumber_ftk, evtnumber_ftk);
+  }
+
+  // first try to start from last number
+  for (; ientry2 < t_truth->GetEntries(); ientry2++) {
+    t_evtinfo->GetEntry(ientry2);
+    if (EventNumber==evtnumber_ftk && RunNumber==runnumber_ftk) break;
+  }
+
+  // only enter this loop if we didn't find it above
+  if (ientry2 == t_truth->GetEntries()) {
+    for (ientry2 = 0; ientry2 < t_truth->GetEntries(); ientry2++) {
+      t_evtinfo->GetEntry(ientry2);
+      if (EventNumber==evtnumber_ftk && RunNumber==runnumber_ftk) break;
+    }
+  }
+
+  if (ientry2 == t_truth->GetEntries()) {
+    ientry2=0;
+    return;
+  }
+
+  t_truth->GetEntry(ientry2);
+
+  // Study the list of the FTK tracks to collect elements for the tracks efficiency
+  Int_t ntracks = tracks->getNTracks();
+  Int_t ntracks_pre_hw = tracks->getNTracks_pre_hw();
+  Int_t ntracksI = tracks->getNTracksI();
+  Int_t ntracksI_pre_hw = tracks->getNTracksI_pre_hw();
+  Int_t ntracks_pattern = tracks->getNTracks_pattern();
+  Int_t ntracks_hits = tracks->getNTracks_hits();
+
+  FTKBarcodeMM ftkmatchinfo;
+  FTKBarcodeMM ftkmatchinfo_pre_hw;
+  FTKBarcodeMM ftkmatchinfoI;
+  FTKBarcodeMM ftkmatchinfoI_pre_hw;
+  FTKBarcodeMM ftkmatchinfo_pattern;
+  FTKBarcodeMM ftkmatchinfo_hits;
+
+  const FTKTrack *curtrack;
+
+
+  // loop over the 2nd-stage FTK tracks
+    for (Int_t itrk=0;itrk!=ntracks;++itrk) { 
+
+      curtrack = tracks->getTrack(itrk);
+
+      double temp_phi = curtrack->getPhi();
+      double temp_z0 = curtrack->getZ0();
+      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+
+      double d0 = curtrack->getIP();
+      double z0 = thisz0;
+      double pt = TMath::Abs(curtrack->getPt())*1e-3;
+      double eta = curtrack->getEta();
+      double phi = curtrack->getPhi();
+      double curv = curtrack->getHalfInvPt()*.5e3;
+      
+      histopt_ftk->Fill(pt);
+      histoeta_ftk->Fill(eta);
+      histophi_ftk->Fill(phi);
+
+      if (curtrack->getEventIndex()==0) {
+        // Information on FTK tracks relative to the hard-scattering events
+        // are collected in a vector and later used to build matching maps
+        if (curtrack->getBarcodeFrac()>.5) {
+          // ftkmatchinfo.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),curtrack->getEventIndex()),curtrack));
+          ftkmatchinfo.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),0),curtrack));
+        }
+      }
+
+      // apply some basic quality selection
+      if (d0<d0min || d0>d0max) continue;
+      if (z0<z0min || z0>z0max) continue;
+      if (phi<phimin || phi > phimax) continue;
+      if (curv<-abscurvmax || curv>abscurvmax) continue;
+      if (eta<etamin || eta>etamax) continue;
+
+      histopt_goodftk->Fill(pt);
+      histoeta_goodftk->Fill(eta);
+      histophi_goodftk->Fill(phi);
+
+      if (curtrack->getBarcodeFrac()<.5) {
+        histopt_goodftkU->Fill(pt);
+        histoeta_goodftkU->Fill(eta);
+        histophi_goodftkU->Fill(phi);
+      }
+
+    } // end loop over the 2nd-stage FTK tracks
+
+
+    // loop over the 2nd-stage FTK tracks before Hit Warrior
+    for (Int_t itrk=0;itrk!=ntracks_pre_hw;++itrk) { 
+
+      curtrack = tracks->getTrack_pre_hw(itrk);
+
+      double temp_phi = curtrack->getPhi();
+      double temp_z0 = curtrack->getZ0();
+      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+
+      double d0 = curtrack->getIP();
+      double z0 = thisz0;
+      double pt = TMath::Abs(curtrack->getPt())*1e-3;
+      double eta = curtrack->getEta();
+      double phi = curtrack->getPhi();
+      double curv = curtrack->getHalfInvPt()*.5e3;
+      
+      histopt_ftk_pre_hw->Fill(pt);
+      histoeta_ftk_pre_hw->Fill(eta);
+      histophi_ftk_pre_hw->Fill(phi);
+
+      if (curtrack->getEventIndex()==0) {
+        // Information on FTK tracks relative to the hard-scattering events
+        // are collected in a vector and later used to build matching maps
+        if (curtrack->getBarcodeFrac()>.5) {
+          // ftkmatchinfo_pre_hw.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),curtrack->getEventIndex()),curtrack));
+          ftkmatchinfo_pre_hw.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),0),curtrack));
+        }
+      }
+
+      // apply some basic quality selection
+      if (d0<d0min || d0>d0max) continue;
+      if (z0<z0min || z0>z0max) continue;
+      if (phi<phimin || phi > phimax) continue;
+      if (curv<-abscurvmax || curv>abscurvmax) continue;
+      if (eta<etamin || eta>etamax) continue;
+
+      histopt_goodftk_pre_hw->Fill(pt);
+      histoeta_goodftk_pre_hw->Fill(eta);
+      histophi_goodftk_pre_hw->Fill(phi);
+
+      if (curtrack->getBarcodeFrac()<.5) {
+        histopt_goodftkU_pre_hw->Fill(pt);
+        histoeta_goodftkU_pre_hw->Fill(eta);
+        histophi_goodftkU_pre_hw->Fill(phi);
+      }
+
+    } // end loop over the 2nd-stage FTK tracks before Hit Warrior
+
+
+    // loop over the 1st-stage FTK tracks
+    for (Int_t itrk=0;itrk!=ntracksI;++itrk) {
+
+      curtrack = tracks->getTrackI(itrk);
+
+      double temp_phi = curtrack->getPhi();
+      double temp_z0 = curtrack->getZ0();
+      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+
+      double d0 = curtrack->getIP();
+      double z0 = thisz0;
+      double pt = TMath::Abs(curtrack->getPt())*1e-3;
+      double eta = curtrack->getEta();
+      double phi = curtrack->getPhi();
+      double curv = curtrack->getHalfInvPt()*.5e3;
+
+      histopt_ftkI->Fill(pt);
+      histoeta_ftkI->Fill(eta);
+      histophi_ftkI->Fill(phi);
+
+      if (curtrack->getEventIndex()==0) {
+        // Information on FTK tracks relative to the hard-scattering events
+        // are collected in a vector and later used to build matching maps
+        if (curtrack->getBarcodeFrac()>.5) {
+          // ftkmatchinfoI.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),curtrack->getEventIndex()),curtrack));
+          ftkmatchinfoI.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),0),curtrack));
+        }
+      }
+
+      // apply some basic quality selection
+      //double d0 = curtrack->getD0();
+      if (d0<d0min || d0>d0max) continue;
+      if (z0<z0min || z0>z0max) continue;
+      if (phi<phimin || phi > phimax) continue;
+      if (curv<-abscurvmax || curv>abscurvmax) continue;
+      if (eta<etamin || eta>etamax) continue;
+
+      histopt_goodftkI->Fill(pt);
+      histoeta_goodftkI->Fill(eta);
+      histophi_goodftkI->Fill(phi);
+
+      if (curtrack->getBarcodeFrac()<.5) {
+        histopt_goodftkUI->Fill(pt);
+        histoeta_goodftkUI->Fill(eta);
+        histophi_goodftkUI->Fill(phi);
+      }
+    } // end loop over the 1st-stage FTK tracks
+
+
+    // loop over the 1st-stage FTK tracks before Hit Warrior
+    for (Int_t itrk=0;itrk!=ntracksI_pre_hw;++itrk) {
+
+      curtrack = tracks->getTrackI_pre_hw(itrk);
+
+      double temp_phi = curtrack->getPhi();
+      double temp_z0 = curtrack->getZ0();
+      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+
+      double d0 = curtrack->getIP();
+      double z0 = thisz0;
+      double pt = TMath::Abs(curtrack->getPt())*1e-3;
+      double eta = curtrack->getEta();
+      double phi = curtrack->getPhi();
+      double curv = curtrack->getHalfInvPt()*.5e3;
+
+      histopt_ftkI_pre_hw->Fill(pt);
+      histoeta_ftkI_pre_hw->Fill(eta);
+      histophi_ftkI_pre_hw->Fill(phi);
+
+      if (curtrack->getEventIndex()==0) {
+        // Information on FTK tracks relative to the hard-scattering events
+        // are collected in a vector and later used to build matching maps
+        if (curtrack->getBarcodeFrac()>.5) {
+          // ftkmatchinfoI_pre_hw.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),curtrack->getEventIndex()),curtrack));
+          ftkmatchinfoI_pre_hw.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),0),curtrack));
+        }
+      }
+
+      // apply some basic quality selection
+      //double d0 = curtrack->getD0();
+      if (d0<d0min || d0>d0max) continue;
+      if (z0<z0min || z0>z0max) continue;
+      if (phi<phimin || phi > phimax) continue;
+      if (curv<-abscurvmax || curv>abscurvmax) continue;
+      if (eta<etamin || eta>etamax) continue;
+
+      histopt_goodftkI_pre_hw->Fill(pt);
+      histoeta_goodftkI_pre_hw->Fill(eta);
+      histophi_goodftkI_pre_hw->Fill(phi);
+
+      if (curtrack->getBarcodeFrac()<.5) {
+        histopt_goodftkUI_pre_hw->Fill(pt);
+        histoeta_goodftkUI_pre_hw->Fill(eta);
+        histophi_goodftkUI_pre_hw->Fill(phi);
+      }
+    } // end loop over the 1st-stage FTK tracks before Hit Warrior
+
+
+    // loop over the FTK tracks with patterns
+    for (Int_t itrk=0;itrk!=ntracks_pattern;++itrk) {
+
+      curtrack = tracks->getTrack_pattern(itrk);
+
+      double temp_phi = curtrack->getPhi();
+      double temp_z0 = curtrack->getZ0();
+      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+
+      double d0 = curtrack->getIP();
+      double z0 = thisz0;
+      double pt = TMath::Abs(curtrack->getPt())*1e-3;
+      double eta = curtrack->getEta();
+      double phi = curtrack->getPhi();
+      double curv = curtrack->getHalfInvPt()*.5e3;
+
+      histopt_ftk_pattern->Fill(pt);
+      histoeta_ftk_pattern->Fill(eta);
+      histophi_ftk_pattern->Fill(phi);
+
+      if (curtrack->getEventIndex()==0) {
+        // Information on FTK tracks relative to the hard-scattering events
+        // are collected in a vector and later used to build matching maps
+        if (curtrack->getBarcodeFrac()>.5) {
+          // ftkmatchinfo_pattern.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),curtrack->getEventIndex()),curtrack));
+          ftkmatchinfo_pattern.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),0),curtrack));
+        }
+      }
+
+      // apply some basic quality selection
+      //double d0 = curtrack->getD0();
+      if (d0<d0min || d0>d0max) continue;
+      if (z0<z0min || z0>z0max) continue;
+      if (phi<phimin || phi > phimax) continue;
+      if (curv<-abscurvmax || curv>abscurvmax) continue;
+      if (eta<etamin || eta>etamax) continue;
+
+      histopt_goodftk_pattern->Fill(pt);
+      histoeta_goodftk_pattern->Fill(eta);
+      histophi_goodftk_pattern->Fill(phi);
+
+      if (curtrack->getBarcodeFrac()<.5) {
+        histopt_goodftkU_pattern->Fill(pt);
+        histoeta_goodftkU_pattern->Fill(eta);
+        histophi_goodftkU_pattern->Fill(phi);
+      }
+    } // end loop over the FTK tracks with patterns
+
+
+    // loop over the FTK tracks passing hits requirements
+    for (Int_t itrk=0;itrk!=ntracks_hits;++itrk) {
+
+      curtrack = tracks->getTrack_hits(itrk);
+
+      double temp_phi = curtrack->getPhi();
+      double temp_z0 = curtrack->getZ0();
+      double thisz0 = temp_z0 + ((cos(temp_phi) *dx - sin(temp_phi)*dy))*curtrack->getCotTheta();
+
+      double d0 = curtrack->getIP();
+      double z0 = thisz0;
+      double pt = TMath::Abs(curtrack->getPt())*1e-3;
+      double eta = curtrack->getEta();
+      double phi = curtrack->getPhi();
+      double curv = curtrack->getHalfInvPt()*.5e3;
+
+      histopt_ftk_hits->Fill(pt);
+      histoeta_ftk_hits->Fill(eta);
+      histophi_ftk_hits->Fill(phi);
+
+      if (curtrack->getEventIndex()==0) {
+        // Information on FTK tracks relative to the hard-scattering events
+        // are collected in a vector and later used to build matching maps
+        if (curtrack->getBarcodeFrac()>.5) {
+          // ftkmatchinfo_hits.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),curtrack->getEventIndex()),curtrack));
+          ftkmatchinfo_hits.insert(pair<MatchInfo, const FTKTrack*>(MatchInfo(curtrack->getBarcode(),0),curtrack));
+        }
+      }
+
+      // apply some basic quality selection
+      //double d0 = curtrack->getD0();
+      if (d0<d0min || d0>d0max) continue;
+      if (z0<z0min || z0>z0max) continue;
+      if (phi<phimin || phi > phimax) continue;
+      if (curv<-abscurvmax || curv>abscurvmax) continue;
+      if (eta<etamin || eta>etamax) continue;
+
+      histopt_goodftk_hits->Fill(pt);
+      histoeta_goodftk_hits->Fill(eta);
+      histophi_goodftk_hits->Fill(phi);
+
+      if (curtrack->getBarcodeFrac()<.5) {
+        histopt_goodftkU_hits->Fill(pt);
+        histoeta_goodftkU_hits->Fill(eta);
+        histophi_goodftkU_hits->Fill(phi);
+      }
+    } // end loop over the FTK tracks passing hits requirements
+
+
+  /*
+   * Study the list of the truth tracks to collect elements useful for the tracks
+   * efficiency
+   */
+  vector<FTKTruthTrack>::const_iterator itr = truthTracks->begin();
+  vector<FTKTruthTrack>::const_iterator itrE = truthTracks->end();
+  for (;itr!=itrE;++itr) { // loop over the truth tracks
+    const FTKTruthTrack &curtruth = (*itr);
+
+    int barcode = curtruth.getBarcode();
+    if (barcode>100000 || barcode==0) continue;
+
+    // select only good truth tracks
+    // double dx = curtruth.getX();
+    // double dy = curtruth.getY();
+    // double d0 = -1e-3*(dx*py-dy*px)*invpt;
+
+    double px = curtruth.getPX();
+    double py = curtruth.getPY();
+    double pt = 1e-3*TMath::Sqrt(px*px+py*py);
+    double invpt = 1./pt;
+    double d0 = curtruth.getD0();
+    double z0 = curtruth.getZ();
+    double curv = .5*curtruth.getQ()*invpt;
+    double phi = curtruth.getPhi();
+    double eta = curtruth.getEta();
+
+    if ( pt < ptmincut ) continue;
+    if (d0<d0min || d0>d0max) continue;
+    if (z0<z0min || z0>z0max) continue;
+    if (curv<-abscurvmax || curv>abscurvmax) continue;
+    if (phi<phimin || phi>phimax) continue;
+    if (eta<etamin || eta>etamax) continue;
+    // if (curtruth.getEventIndex()!=0 && curtruth.getQ()==0) continue;
+    if (curtruth.getQ()==0) continue;
+
+    // Fill the histogram for the generic truth distribution
+    histopt_truth->Fill(pt);
+    histoeta_truth->Fill(eta);
+    histophi_truth->Fill(phi);
+
+    // match the barcode and event index values
+    // MatchInfo reftruth(barcode,curtruth.getEventIndex());
+    MatchInfo reftruth(barcode,0);
+    pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrange = ftkmatchinfo.equal_range(reftruth);
+    pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrange_pre_hw = ftkmatchinfo_pre_hw.equal_range(reftruth);
+    pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrangeI = ftkmatchinfoI.equal_range(reftruth);
+    pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrangeI_pre_hw = ftkmatchinfoI_pre_hw.equal_range(reftruth);
+    pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrange_pattern = ftkmatchinfo_pattern.equal_range(reftruth);
+    pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrange_hits = ftkmatchinfo_hits.equal_range(reftruth);
+
+    if (mrange.first != mrange.second) {
+      histopt_truthM->Fill(pt);
+      histoeta_truthM->Fill(eta);
+      histophi_truthM->Fill(phi);      
+    }
+    if (mrange_pre_hw.first != mrange_pre_hw.second) {
+      histopt_truthM_pre_hw->Fill(pt);
+      histoeta_truthM_pre_hw->Fill(eta);
+      histophi_truthM_pre_hw->Fill(phi);      
+    }
+    if (mrangeI.first != mrangeI.second) {
+      histopt_truthMI->Fill(pt);
+      histoeta_truthMI->Fill(eta);
+      histophi_truthMI->Fill(phi);
+      pair<FTKBarcodeMM::const_iterator,FTKBarcodeMM::const_iterator> mrange_cond = ftkmatchinfo.equal_range(reftruth);
+      if (mrange_cond.first != mrange_cond.second) {
+        histopt_truthM_cond->Fill(pt);  
+        histoeta_truthM_cond->Fill(eta);
+        histophi_truthM_cond->Fill(phi);    
+      }
+    }
+    if (mrangeI_pre_hw.first != mrangeI_pre_hw.second) {
+      histopt_truthMI_pre_hw->Fill(pt);
+      histoeta_truthMI_pre_hw->Fill(eta);
+      histophi_truthMI_pre_hw->Fill(phi);     
+    }
+    if (mrange_pattern.first != mrange_pattern.second) {
+      histopt_truthM_pattern->Fill(pt);
+      histoeta_truthM_pattern->Fill(eta);
+      histophi_truthM_pattern->Fill(phi);     
+    }
+    if (mrange_hits.first != mrange_hits.second) {
+      histopt_truthM_hits->Fill(pt);
+      histoeta_truthM_hits->Fill(eta);
+      histophi_truthM_hits->Fill(phi);     
+    }
+  } // end loop over truth tracks
+
+}
+
+
+void Terminate(std::string& outputname) {
+
+  Info("Terminate","Adding the histograms to the file: %s", outputname.c_str());
+  TFile *ofile = TFile::Open(outputname.c_str(), "recreate");
+
+  // calculate some efficiency plots
+ 
+  TGraphAsymmErrors *greffpt = new TGraphAsymmErrors(histopt_truthM,histopt_truth);
+  greffpt->SetNameTitle("greffpt",";p_{T} (GeV);2nd-stage Merger Efficiency w.r.t. Truth");
+  ofile->Add(greffpt);
+  TGraphAsymmErrors *greffeta = new TGraphAsymmErrors(histoeta_truthM,histoeta_truth);
+  greffeta->SetNameTitle("greffeta",";#eta;2nd-stage Merger Efficiency w.r.t. Truth");
+  ofile->Add(greffeta);
+  TGraphAsymmErrors *greffphi = new TGraphAsymmErrors(histophi_truthM,histophi_truth);
+  greffphi->SetNameTitle("greffphi",";#phi (rad);2nd-stage Merger Efficiency w.r.t. Truth");
+  ofile->Add(greffphi);
+
+  TGraphAsymmErrors *greffpt_pre_hw = new TGraphAsymmErrors(histopt_truthM_pre_hw,histopt_truth);
+  greffpt_pre_hw->SetNameTitle("greffpt_pre_hw",";p_{T} (GeV);2nd-stage Fitter Efficiency w.r.t. Truth");
+  ofile->Add(greffpt_pre_hw);
+  TGraphAsymmErrors *greffeta_pre_hw = new TGraphAsymmErrors(histoeta_truthM_pre_hw,histoeta_truth);
+  greffeta_pre_hw->SetNameTitle("greffeta_pre_hw",";#eta;2nd-stage Fitter Efficiency w.r.t. Truth");
+  ofile->Add(greffeta_pre_hw);
+  TGraphAsymmErrors *greffphi_pre_hw = new TGraphAsymmErrors(histophi_truthM_pre_hw,histophi_truth);
+  greffphi_pre_hw->SetNameTitle("greffphi_pre_hw",";#phi (rad);2nd-stage Fitter Efficiency w.r.t. Truth");
+  ofile->Add(greffphi_pre_hw);
+
+  TGraphAsymmErrors *greffptI = new TGraphAsymmErrors(histopt_truthMI,histopt_truth);
+  greffptI->SetNameTitle("greffptI",";p_{T} (GeV);1nd-stage Merger Efficiency w.r.t. Truth");
+  ofile->Add(greffptI);
+  TGraphAsymmErrors *greffetaI = new TGraphAsymmErrors(histoeta_truthMI,histoeta_truth);
+  greffetaI->SetNameTitle("greffetaI",";#eta;1nd-stage Merger Efficiency w.r.t. Truth");
+  ofile->Add(greffetaI);
+  TGraphAsymmErrors *greffphiI = new TGraphAsymmErrors(histophi_truthMI,histophi_truth);
+  greffphiI->SetNameTitle("greffphiI",";#phi (rad);1nd-stage Merger Efficiency w.r.t. Truth");
+  ofile->Add(greffphiI);
+
+  TGraphAsymmErrors *greffptI_pre_hw = new TGraphAsymmErrors(histopt_truthMI_pre_hw,histopt_truth);
+  greffptI_pre_hw->SetNameTitle("greffptI_pre_hw",";p_{T} (GeV);1nd-stage Fitter Efficiency w.r.t. Truth");
+  ofile->Add(greffptI_pre_hw);
+  TGraphAsymmErrors *greffetaI_pre_hw = new TGraphAsymmErrors(histoeta_truthMI_pre_hw,histoeta_truth);
+  greffetaI_pre_hw->SetNameTitle("greffetaI_pre_hw",";#eta;1nd-stage Fitter Efficiency w.r.t. Truth");
+  ofile->Add(greffetaI_pre_hw);
+  TGraphAsymmErrors *greffphiI_pre_hw = new TGraphAsymmErrors(histophi_truthMI_pre_hw,histophi_truth);
+  greffphiI_pre_hw->SetNameTitle("greffphiI_pre_hw",";#phi (rad);1nd-stage Fitter Efficiency w.r.t. Truth");
+  ofile->Add(greffphiI_pre_hw);
+
+  TGraphAsymmErrors *greffpt_pattern = new TGraphAsymmErrors(histopt_truthM_pattern,histopt_truth);
+  greffpt_pattern->SetNameTitle("greffpt_pattern",";p_{T} (GeV);Bank Efficiency w.r.t. Truth");
+  ofile->Add(greffpt_pattern);
+  TGraphAsymmErrors *greffeta_pattern = new TGraphAsymmErrors(histoeta_truthM_pattern,histoeta_truth);
+  greffeta_pattern->SetNameTitle("greffeta_pattern",";#eta;Bank Efficiency w.r.t. Truth");
+  ofile->Add(greffeta_pattern);
+  TGraphAsymmErrors *greffphi_pattern = new TGraphAsymmErrors(histophi_truthM_pattern,histophi_truth);
+  greffphi_pattern->SetNameTitle("greffphi_pattern",";#phi (rad);Bank Efficiency w.r.t. Truth");
+  ofile->Add(greffphi_pattern);
+
+  TGraphAsymmErrors *greffpt_hits = new TGraphAsymmErrors(histopt_truthM_hits,histopt_truth);
+  greffpt_hits->SetNameTitle("greffpt_hits",";p_{T} (GeV);Configuration Efficiency w.r.t. Truth");
+  ofile->Add(greffpt_hits);
+  TGraphAsymmErrors *greffeta_hits = new TGraphAsymmErrors(histoeta_truthM_hits,histoeta_truth);
+  greffeta_hits->SetNameTitle("greffeta_hits",";#eta;Configuration Efficiency w.r.t. Truth");
+  ofile->Add(greffeta_hits);
+  TGraphAsymmErrors *greffphi_hits = new TGraphAsymmErrors(histophi_truthM_hits,histophi_truth);
+  greffphi_hits->SetNameTitle("greffphi_hits",";#phi (rad);Configuration Efficiency w.r.t. Truth");
+  ofile->Add(greffphi_hits);
+
+  TGraphAsymmErrors *greffpt_cond = new TGraphAsymmErrors(histopt_truthM_cond,histopt_truthMI);
+  greffpt_cond->SetNameTitle("greffpt_cond",";p_{T} (GeV);2nd-stage Merger Efficiency w.r.t 1st stage");
+  ofile->Add(greffpt_cond);
+  TGraphAsymmErrors *greffeta_cond = new TGraphAsymmErrors(histoeta_truthM_cond,histoeta_truthMI);
+  greffeta_cond->SetNameTitle("greffeta_cond",";#eta;2nd-stage Merger Efficiency w.r.t 1st stage");
+  ofile->Add(greffeta_cond);
+  TGraphAsymmErrors *greffphi_cond = new TGraphAsymmErrors(histophi_truthM_cond,histophi_truthMI);
+  greffphi_cond->SetNameTitle("greffphi_cond",";#phi (rad);2nd-stage Merger Efficiency w.r.t 1st stage");
+  ofile->Add(greffphi_cond);
+
+
+  TGraphAsymmErrors *grfakept = new TGraphAsymmErrors(histopt_goodftkU,histopt_goodftk);
+  grfakept->SetNameTitle("grfakept",";p_{T} (GeV);2nd-stage Merger Fake Rate");
+  ofile->Add(grfakept);
+  TGraphAsymmErrors *grfakeeta = new TGraphAsymmErrors(histoeta_goodftkU,histoeta_goodftk);
+  grfakeeta->SetNameTitle("grfakeeta",";#eta;2nd-stage Merger Fake Rate");
+  ofile->Add(grfakeeta);
+  TGraphAsymmErrors *grfakephi = new TGraphAsymmErrors(histophi_goodftkU,histophi_goodftk);
+  grfakephi->SetNameTitle("grfakephi",";#phi (rad);2nd-stage Merger Fake Rate");
+  ofile->Add(grfakephi);
+
+  TGraphAsymmErrors *grfakept_pre_hw = new TGraphAsymmErrors(histopt_goodftkU_pre_hw,histopt_goodftk_pre_hw);
+  grfakept_pre_hw->SetNameTitle("grfakept_pre_hw",";p_{T} (GeV);2nd-stage Fitter Fake Rate");
+  ofile->Add(grfakept_pre_hw);
+  TGraphAsymmErrors *grfakeeta_pre_hw = new TGraphAsymmErrors(histoeta_goodftkU_pre_hw,histoeta_goodftk_pre_hw);
+  grfakeeta_pre_hw->SetNameTitle("grfakeeta_pre_hw",";#eta;2nd-stage Fitter Fake Rate");
+  ofile->Add(grfakeeta_pre_hw);
+  TGraphAsymmErrors *grfakephi_pre_hw = new TGraphAsymmErrors(histophi_goodftkU_pre_hw,histophi_goodftk_pre_hw);
+  grfakephi_pre_hw->SetNameTitle("grfakephi_pre_hw",";#phi (rad);2nd-stage Fitter Fake Rate");
+  ofile->Add(grfakephi_pre_hw);
+
+  TGraphAsymmErrors *grfakeptI = new TGraphAsymmErrors(histopt_goodftkUI,histopt_goodftkI);
+  grfakeptI->SetNameTitle("grfakeptI",";p_{T} (GeV);1st-stage Merger Fake Rate");
+  ofile->Add(grfakeptI);
+  TGraphAsymmErrors *grfakeetaI = new TGraphAsymmErrors(histoeta_goodftkUI,histoeta_goodftkI);
+  grfakeetaI->SetNameTitle("grfakeetaI",";#eta;1st-stage Merger Fake Rate");
+  ofile->Add(grfakeetaI);
+  TGraphAsymmErrors *grfakephiI = new TGraphAsymmErrors(histophi_goodftkUI,histophi_goodftkI);
+  grfakephiI->SetNameTitle("grfakephiI",";#phi (rad);1st-stage Merger Fake Rate");
+  ofile->Add(grfakephiI);
+
+  TGraphAsymmErrors *grfakeptI_pre_hw = new TGraphAsymmErrors(histopt_goodftkUI_pre_hw,histopt_goodftkI_pre_hw);
+  grfakeptI_pre_hw->SetNameTitle("grfakeptI_pre_hw",";p_{T} (GeV);1st-stage Fitter Fake Rate");
+  ofile->Add(grfakeptI_pre_hw);
+  TGraphAsymmErrors *grfakeetaI_pre_hw = new TGraphAsymmErrors(histoeta_goodftkUI_pre_hw,histoeta_goodftkI_pre_hw);
+  grfakeetaI_pre_hw->SetNameTitle("grfakeetaI_pre_hw",";#eta;1st-stage Fitter Fake Rate");
+  ofile->Add(grfakeetaI_pre_hw);
+  TGraphAsymmErrors *grfakephiI_pre_hw = new TGraphAsymmErrors(histophi_goodftkUI_pre_hw,histophi_goodftkI_pre_hw);
+  grfakephiI_pre_hw->SetNameTitle("grfakephiI_pre_hw",";#phi (rad);1st-stage Fitter Fake Rate");
+  ofile->Add(grfakephiI_pre_hw);
+
+  TGraphAsymmErrors *grfakept_pattern = new TGraphAsymmErrors(histopt_goodftkU_pattern,histopt_goodftk_pattern);
+  grfakept_pattern->SetNameTitle("grfakept_pattern",";p_{T} (GeV);Bank Fake Rate");
+  ofile->Add(grfakept_pattern);
+  TGraphAsymmErrors *grfakeeta_pattern = new TGraphAsymmErrors(histoeta_goodftkU_pattern,histoeta_goodftk_pattern);
+  grfakeeta_pattern->SetNameTitle("grfakeeta_pattern",";#eta;Bank Fake Rate");
+  ofile->Add(grfakeeta_pattern);
+  TGraphAsymmErrors *grfakephi_pattern = new TGraphAsymmErrors(histophi_goodftkU_pattern,histophi_goodftk_pattern);
+  grfakephi_pattern->SetNameTitle("grfakephi_pattern",";#phi (rad);Bank Fake Rate");
+  ofile->Add(grfakephi_pattern);
+
+  TGraphAsymmErrors *grfakept_hits = new TGraphAsymmErrors(histopt_goodftkU_hits,histopt_goodftk_hits);
+  grfakept_hits->SetNameTitle("grfakept_hits",";p_{T} (GeV);Configuration Fake Rate");
+  ofile->Add(grfakept_hits);
+  TGraphAsymmErrors *grfakeeta_hits = new TGraphAsymmErrors(histoeta_goodftkU_hits,histoeta_goodftk_hits);
+  grfakeeta_hits->SetNameTitle("grfakeeta_hits",";#eta;Configuration Fake Rate");
+  ofile->Add(grfakeeta_hits);
+  TGraphAsymmErrors *grfakephi_hits = new TGraphAsymmErrors(histophi_goodftkU_hits,histophi_goodftk_hits);
+  grfakephi_hits->SetNameTitle("grfakephi_hits",";#phi (rad);Configuration Fake Rate");
+  ofile->Add(grfakephi_hits);
+
+  ofile->Add(histopt_truth);
+  ofile->Add(histopt_truthM);
+
+  ofile->ls();
+  ofile->Write();
+  ofile->Close();
+
+}
+
+int main(int argc, char **argv) {
+  int events;
+  std::string output;
+  std::vector<std::string> files;
+  ptmincut = 0;
+  dx = -0.5;
+  dy = -0.5;
+
+  try {
+    std::string appName = boost::filesystem::basename(argv[0]);
+    // Define and parse the program options
+    namespace po = boost::program_options;
+    po::options_description desc("Options");
+    desc.add_options()
+      ("help,h", "Print this help message")
+      ("output,o", po::value<std::string>(&output)->default_value("ftk_efficiency.root"), "The name out of the output file")
+      ("events,e", po::value<int>(&events)->default_value(-1), "The number of events to run over. Set to -1 to use all events")
+      ("tower,t", po::value<int>(&towerNumber)->default_value(-1), "the number of the tower in ftkdata output data. Use -1 if you have fully merged output")
+      ("files", po::value<std::vector<std::string> >(&files)->multitoken(), "FTK NTUP files")
+      ("ptmincut", po::value<double>(&ptmincut), "min pt cut on truth tracks")
+      ("dx", po::value<double>(&dx)->default_value(-0.5), "dx")
+      ("dy", po::value<double>(&dy)->default_value(-0.5), "dx");
+
+    po::variables_map vm;
+    try
+    {
+      po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
+      // --help option
+      if (vm.count("help"))
+      {
+        cout << desc << "\n";
+        return 1;
+      }
+      po::notify(vm);
+    }
+    catch(std::exception& e)
+    {
+      std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
+      return 1;
+    }
+
+    Init();
+    t_ftkdata = new TChain("ftkdata");
+    t_truth = new TChain("truthtracks");
+    t_evtinfo = new TChain("evtinfo");
+
+    // add the input files
+    std::vector<std::string>::const_iterator files_it = files.begin();
+    for (; files_it != files.end(); ++files_it) {
+      t_ftkdata->Add((*files_it).c_str());
+      t_truth->Add((*files_it).c_str());
+      t_evtinfo->Add((*files_it).c_str());
+    }
+
+    t_ftkdata->AddFriend(t_truth);
+    t_ftkdata->AddFriend(t_evtinfo);
+    t_evtinfo->SetBranchAddress("RunNumber",&RunNumber);
+    t_evtinfo->SetBranchAddress("EventNumber",&EventNumber);
+    //  t_ftkdata->SetBranchAddress("FTKMergedTracksStream",&tracks);
+    if (towerNumber != -1) {
+      t_ftkdata->SetBranchAddress(Form("FTKMergedTracksStream%d",towerNumber),&tracks);
+    } else {
+      t_ftkdata->SetBranchAddress(Form("FTKMergedTracksStream"),&tracks);
+    }
+
+    t_truth->SetBranchAddress("TruthTracks",&truthTracks);
+
+    Int_t nloop = t_ftkdata->GetEntries();
+    if (events > 0) {
+      nloop = events;
+    }
+    if (nloop > t_ftkdata->GetEntries()) {
+      nloop = t_ftkdata->GetEntries();
+    }
+    for (int ientry = 0; ientry < nloop; ++ientry) {
+      Process(ientry);
+    }
+    Terminate(output);
+  } // end try
+  catch(std::exception& e)
+  {
+    std::cerr << "Unhandled Exception reached the top of main: "
+              << e.what() << ", application will now exit" << std::endl;
+    return 1;
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.h b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.h
new file mode 100644
index 000000000000..a4a0fc998baa
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/efficiency_step_by_step.h
@@ -0,0 +1,172 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include <TMath.h>
+#include <TH2F.h>
+#include <TGraphAsymmErrors.h>
+#include <map>
+#include <iostream>
+#include "../TrigFTKSim/FTKTrackStream.h"
+#include "../TrigFTKSim/FTKRoadStream.h"
+#include "../TrigFTKSim/FTKTruthTrack.h"
+#include "TChain.h"
+#include "TFile.h"
+#include "TProfile.h"
+
+using namespace std;
+
+class MatchInfo {
+// private:
+//   int m_barcode;
+//   int m_evtindex;
+
+public:
+  int m_barcode;
+  int m_evtindex;
+  MatchInfo() : m_barcode(0), m_evtindex(-1) {;}
+  MatchInfo(int v1, int v2) : m_barcode(v1), m_evtindex(v2) {;}
+  bool operator==(const MatchInfo& o) const { return (m_barcode==o.m_barcode)&&(m_evtindex==o.m_evtindex); }
+  bool operator<(const MatchInfo& o) const { if (m_evtindex!=o.m_evtindex) return (m_evtindex<o.m_evtindex); else return m_barcode<o.m_barcode; }
+};
+
+typedef multimap<MatchInfo,const FTKTrack*> FTKBarcodeMM;
+unsigned nbins;
+double maxntracks;
+double d0min, d0max;
+double z0min, z0max;
+double phimin, phimax;
+double etamin, etamax;
+double abscurvmax;
+double ptmax;
+double Dd0;
+double Dphi;
+double Drelpt;
+double Dcurv;
+double Deta;
+double Dz0;
+double ptmincut;
+double dx, dy;
+
+// block of generic control histograms for the FTK tracks
+TH1F *histopt_ftk;
+TH1F *histoeta_ftk;
+TH1F *histophi_ftk;
+
+TH1F *histopt_ftk_pre_hw;
+TH1F *histoeta_ftk_pre_hw;
+TH1F *histophi_ftk_pre_hw;
+
+TH1F *histopt_ftkI;
+TH1F *histoeta_ftkI;
+TH1F *histophi_ftkI;
+
+TH1F *histopt_ftkI_pre_hw;
+TH1F *histoeta_ftkI_pre_hw;
+TH1F *histophi_ftkI_pre_hw;
+
+TH1F *histopt_ftk_pattern;
+TH1F *histoeta_ftk_pattern;
+TH1F *histophi_ftk_pattern;
+
+TH1F *histopt_ftk_hits;
+TH1F *histoeta_ftk_hits;
+TH1F *histophi_ftk_hits;
+
+// FTK for fakes
+TH1F *histopt_goodftk;
+TH1F *histoeta_goodftk;
+TH1F *histophi_goodftk;
+
+TH1F *histopt_goodftk_pre_hw;
+TH1F *histoeta_goodftk_pre_hw;
+TH1F *histophi_goodftk_pre_hw;
+
+TH1F *histopt_goodftkI;
+TH1F *histoeta_goodftkI;
+TH1F *histophi_goodftkI;
+
+TH1F *histopt_goodftkI_pre_hw;
+TH1F *histoeta_goodftkI_pre_hw;
+TH1F *histophi_goodftkI_pre_hw;
+
+TH1F *histopt_goodftk_pattern;
+TH1F *histoeta_goodftk_pattern;
+TH1F *histophi_goodftk_pattern;
+
+TH1F *histopt_goodftk_hits;
+TH1F *histoeta_goodftk_hits;
+TH1F *histophi_goodftk_hits;
+
+
+TH1F *histopt_goodftkU;
+TH1F *histoeta_goodftkU;
+TH1F *histophi_goodftkU;
+
+TH1F *histopt_goodftkU_pre_hw;
+TH1F *histoeta_goodftkU_pre_hw;
+TH1F *histophi_goodftkU_pre_hw;
+
+TH1F *histopt_goodftkUI;
+TH1F *histoeta_goodftkUI;
+TH1F *histophi_goodftkUI;
+
+TH1F *histopt_goodftkUI_pre_hw;
+TH1F *histoeta_goodftkUI_pre_hw;
+TH1F *histophi_goodftkUI_pre_hw;
+
+TH1F *histopt_goodftkU_pattern;
+TH1F *histoeta_goodftkU_pattern;
+TH1F *histophi_goodftkU_pattern;
+
+TH1F *histopt_goodftkU_hits;
+TH1F *histoeta_goodftkU_hits;
+TH1F *histophi_goodftkU_hits;
+
+// block of distribution related to truth tracks
+TH1F *histopt_truth;
+TH1F *histoeta_truth;
+TH1F *histophi_truth;
+
+TH1F *histopt_truthM;
+TH1F *histoeta_truthM;
+TH1F *histophi_truthM;
+
+TH1F *histopt_truthM_pre_hw;
+TH1F *histoeta_truthM_pre_hw;
+TH1F *histophi_truthM_pre_hw;
+
+TH1F *histopt_truthMI;
+TH1F *histoeta_truthMI;
+TH1F *histophi_truthMI;
+
+TH1F *histopt_truthMI_pre_hw;
+TH1F *histoeta_truthMI_pre_hw;
+TH1F *histophi_truthMI_pre_hw;
+
+TH1F *histopt_truthM_pattern;
+TH1F *histoeta_truthM_pattern;
+TH1F *histophi_truthM_pattern;
+
+TH1F *histopt_truthM_hits;
+TH1F *histoeta_truthM_hits;
+TH1F *histophi_truthM_hits;
+
+TH1F *histopt_truthM_cond;
+TH1F *histoeta_truthM_cond;
+TH1F *histophi_truthM_cond;
+
+// Things to access variables!
+FTKTrackStream *tracks(0);
+FTKRoadStream *roads(0);
+std::vector<FTKTruthTrack> *truthTracks(0);
+Int_t RunNumber, EventNumber;
+TChain *t_ftkdata;
+TChain *t_truth;
+TChain *t_evtinfo;
+
+int towerNumber;
+/* TString outputname; */
+std::string outputname;
+std::string psfile;
+int ientry2;
\ No newline at end of file
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/make_conn.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/make_conn.cc
new file mode 100644
index 000000000000..c4d1ab49b3ac
--- /dev/null
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/make_conn.cc
@@ -0,0 +1,232 @@
+#include <iostream>
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+
+#include <TString.h>
+
+#include <glob.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <boost/iostreams/device/file.hpp>
+//#include <boost/iostreams/concepts.hpp>
+//#include <boost/iostreams/categories.hpp>
+//#include <boost/algorithm/string/classification.hpp>
+//#include <boost/filesystem.hpp> 
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/filter/bzip2.hpp>
+
+using namespace std;
+
+class SSIDvector : public vector<int> {
+public:
+   SSIDvector(int n=0) : vector<int>(n) { }
+   int operator<(const SSIDvector &b) const {
+      if(size()<b.size()) return true;
+      if(size()>b.size()) return false;
+      for(size_t n=0;n<size();n++) {
+         if((*this)[n]<b[n]) return true;
+         if((*this)[n]>b[n]) return false;
+      }
+      return false;
+   }
+};
+
+typedef map<SSIDvector,pair<int,vector<vector<int> > > >  ConnectionMap_t;
+
+int main(int argc, char const *argv[]) {
+   if(argc!=2) {
+      cout<<"usage: "<<argv[0]<<" path\n";
+      exit(0);
+   }
+   TString path(argv[1]);
+   //
+   // locate 8L sector files
+   glob_t globList;
+   struct stat statBuf;
+   memset(&globList,0,sizeof(glob_t));
+   TString sector8Lpath=path+"/sectors_raw_8L_reg*";
+   int err=glob(sector8Lpath,GLOB_TILDE,0,&globList);
+   if(err) {
+      cout<<"Error: can not glob "<<sector8Lpath<<"\n";
+      exit(1);
+   }
+   int nTowerMax=globList.gl_pathc;
+   for(int tower=0;tower<nTowerMax;tower++) {
+      sector8Lpath=path+TString::Format("/sectors_raw_8L_reg%d.patt*",tower);
+      memset(&globList,0,sizeof(glob_t));
+      err=glob(sector8Lpath,GLOB_TILDE,0,&globList);
+      if(err) {
+         cout<<"Can not glob "<<sector8Lpath<<", skipping\n";
+         continue;
+      }
+      TString sectorFile[2];
+      sectorFile[0]=globList.gl_pathv[0];
+      TString sector12Lpath=path+
+         TString::Format("/sectors_raw_12L_reg%d.patt*",tower);
+      memset(&globList,0,sizeof(glob_t));
+      err=glob(sector12Lpath,GLOB_TILDE,0,&globList);
+      if(err) {
+         cout<<"Can not glob "<<sector12Lpath<<", skipping\n";
+         continue;
+      }
+      sectorFile[1]=globList.gl_pathv[0];
+      int error=0;
+      boost::iostreams::filtering_istream *sectorStream[2];
+      for(int i=0;i<2;i++) {
+         if(stat(sectorFile[i],&statBuf)) {
+            cout<<"Can not stat "<<sectorFile[i]<<", skipping\n";
+            error++;
+         }
+         if(!S_ISREG(statBuf.st_mode)) {
+            cout<<"Not a regular file, skipping: "
+                <<sectorFile[i]<<"\n";
+            error++;
+         }
+         sectorStream[i]=new boost::iostreams::filtering_istream;
+         if(sectorFile[i].EndsWith(".bz2")) {
+            sectorStream[i]->push(boost::iostreams::bzip2_decompressor());
+         }
+         sectorStream[i]->push(boost::iostreams::file_source(sectorFile[i].Data()));
+         cout<<"open "<<sectorFile[i]<<"\n";
+      }
+      if(error) continue;
+      // read sector files
+      
+      vector<set<int> > moduleId;
+      ConnectionMap_t connections; 
+      int notFound=0;
+      int found=0;
+      for(int iType=0;iType<2;iType++) {
+         int nSector,nPlane;
+         (*sectorStream[iType])>>nSector>>nPlane;
+         if(iType==0) moduleId.resize(nPlane);
+         SSIDvector ssid(nPlane);
+         for(int iSector=0;iSector<nSector;iSector++) {
+            // read sector data
+            int sectorID;
+            (*sectorStream[iType])>>sectorID;
+            //cout<<sectorID;
+            if(sectorID!=iSector) {
+               cout<<"error reading sector "<<iSector
+                   <<" "<<sectorID<<"\n";
+               exit(0);
+            }
+            // read module IDs
+            for(int plane=0;plane<nPlane;plane++) {
+               (*sectorStream[iType])>>ssid[plane];
+               //cout<<" "<<ssid[plane];
+            }
+            // dummy
+            int dummy,nTrack;
+            (*sectorStream[iType])>>dummy>>nTrack;
+            //cout<<" "<<dummy<<" "<<nTrack<<"\n";
+            //if(sectorID>20) exit(0);
+            SSIDvector ssid8L(moduleId.size());
+            if(iType==0) {
+               // if 8L: store known module IDs and store 8L SSID
+               for(int plane=0;plane<nPlane;plane++) {
+                  moduleId[plane].insert(ssid[plane]);
+                  ssid8L[plane]=ssid[plane];
+               }
+               connections[ssid8L].first=iSector;
+            } else {
+               // if 12L:  locate known planes, skip others
+               vector<int> connId(nPlane-moduleId.size()+2);
+               connId[1]=iSector;
+               size_t nExtra=2;
+               size_t plane8=0;
+               for(int plane=0;plane<nPlane;plane++) {
+                  if((plane8<moduleId.size())&&
+                     (moduleId[plane8].find(ssid[plane])!=
+                      moduleId[plane8].end())) {
+                     //cout<<" "<<ssid[plane]<<" "<<plane<<" -> "<<plane8<<"\n";
+                     ssid8L[plane8++]=ssid[plane];
+                  } else {
+                     if(nExtra>=connId.size()) {
+                        cout<<"12L sector="<<iSector<<" too few planes match\n";
+                        exit(0);
+                     }
+                     //cout<<" "<<ssid[plane]<<" extra="<<nExtra<<"\n";
+                     connId[nExtra++]=ssid[plane];
+                  }
+               }
+               //exit(0);
+               ConnectionMap_t::iterator ic=connections.find(ssid8L);
+
+               /* cout<<" 8L:";
+                  for(int k=0;k<ssid8L.size();k++) {
+                     cout<<" "<<ssid8L[k];
+                  }
+                  cout<<" extra ";
+                  for(int k=0;k<connId.size();k++) {
+                     cout<<" "<<connId[k];
+                  }
+                  cout<<"\n";
+               */
+               if(ic==connections.end()) {
+                  notFound++;
+                  //cout<<"Number of sectors: "<<connections.size()<<"\n";
+                  //cout<<"12L sector="<<iSector<<" not found, skipping\n";
+                  /* for(ConnectionMap_t::const_iterator ic=connections.begin();
+                      ic!=connections.end();ic++) {
+                     if((*ic).second.first<20) {
+                        cout<<(*ic).second.first;
+                        for(int k=0;k<(*ic).first.size();k++) {
+                           cout<<" "<<(*ic).first[k];
+                        }
+                        cout<<"\n";
+                     }
+                  }
+                  exit(0); */
+               } else {
+                  found++;
+                  vector<vector<int> > &conn12=(*ic).second.second;
+                  conn12.push_back(connId);
+               }
+            }
+         }
+         if(iType==0) {
+            cout<<"nSector="<<nSector<<" nPlane="<<nPlane
+                <<" Number of sectors: "<<connections.size()<<"\n";
+            for(size_t plane=0;plane< moduleId.size();plane++) {
+               cout<<" 8L["<<plane<<"] n(mod)="<<moduleId[plane].size();
+            }
+            cout<<"\n";
+         } else {
+            cout<<"nSector="<<nSector<<" nPlane="<<nPlane
+                <<" notFound="<<notFound<<" found="<<found<<"\n";
+            // order connections by sector id, then print
+            map<int,ConnectionMap_t::const_iterator> orderedConnections;
+            for(ConnectionMap_t::const_iterator ic=connections.begin();
+                ic!=connections.end();ic++) {
+               orderedConnections[(*ic).second.first]=ic;
+            }
+            TString outname(TString::Format("sectors_raw_8L_reg%d.conn",tower));
+            ofstream output(outname);
+            int sectorID12=0;
+            for(map<int,ConnectionMap_t::const_iterator>::const_iterator
+                   oic=orderedConnections.begin();
+                oic!=orderedConnections.end();oic++) {
+               vector<vector<int> > const &conn12=(*(*oic).second).second.second;
+               output<<(*oic).first<<" "<<conn12.size();
+               for(size_t k=0;k<conn12.size();k++) {
+                  output<<" 0 "<<sectorID12;
+                  sectorID12++;
+                  for(size_t l=2;l<conn12[k].size();l++) {
+                     output<<" "<<conn12[k][l];
+                  }
+               }
+               output<<"\n";
+            }
+         }
+      }
+
+      for(int i=0;i<2;i++) {
+         delete sectorStream[i];
+      }
+   }
+}
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/makecompressedbank.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/makecompressedbank.cc
index 402ef0e8a205..408240caa78b 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/makecompressedbank.cc
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/makecompressedbank.cc
@@ -23,22 +23,14 @@ LOGGING_PRINT_LEVEL 4
 #  level 3: stop if FATAL,ERROR,WARNING
 LOGGING_ABORT_LEVEL 2
 #
-####### options specific to makesmallbank
+####### options specific to makecompressedbank
 #
-# input files: TTree "Bank" with objects FTKPattern
-NINPUTS 1
-# first file (text)
-bank.pcache.root
-
+TOWER 0
 # output/input file
 #   format written by FTKTSPBank
 PCACHEIN patterns.pcache.root
 PCACHEOUT cached.root
 #
-#   binary format (not compatible)
-# BINARYIN ssidFile.bin
-BINARYOUT ssidFile.bin
-#
 # binarylookup-tables output file
 CCACHEIN ssidFile.root
 CCACHEOUT ssidFile.root
@@ -83,9 +75,9 @@ using namespace std;
 #define PMAP "PMAP"
 #define RMAP "RMAP"
 #define SSMAP "SSMAP"
+#define IBLMODE "IBLMODE"
+#define MODULELUTPATH "MODULELUTPATH"
 #define TSP_SSMAP "TSP_SSMAP"
-#define BINARYIN "BINARYIN"
-#define BINARYOUT "BINARYOUT"
 #define CCACHEIN "CCACHEIN"
 #define CCACHEOUT "CCACHEOUT"
 #define MAXPATT "MAXPATT"
@@ -99,109 +91,109 @@ using namespace std;
 class MakeSmallBankSteering : public FTKSteering {
 public:
    static MakeSmallBankSteering *Instance(void) {
-      if(!fSteering) {
-         fSteering=new MakeSmallBankSteering();
-         fSteering->AddIntPar(TOWER,1,-1);
-         fSteering->AddStringPar(PCACHEIN,1);
-         fSteering->AddStringPar(PCACHEOUT,1);
-         fSteering->AddStringPar(BINARYIN,1);
-         fSteering->AddStringPar(BINARYOUT,1);
-         fSteering->AddStringPar(CCACHEIN,1);
-         fSteering->AddStringPar(CCACHEOUT,1);
-         fSteering->AddIntPar(MAXPATT,1,-1);
-         fSteering->AddStringPar(ROOTIN,1);
-         fSteering->AddStringPar(PMAP,1,
-				 "../config/map_file/raw_8LcIbl123.pmap");
-         fSteering->AddStringPar(RMAP,1,
-				 "../config/map_file/raw_12Libl.tmap");
-         fSteering->AddStringPar(SSMAP,1,
-				 "../config/ss_file/raw_30x32x72Ibl.ss");
-         fSteering->AddStringPar(TSP_SSMAP,1,
-				 "../config/ss_file/raw_15x16x36Ibl.ss");
-         fSteering->AddDoublePar(TSP_SSID,0);
-         fSteering->AddDoublePar(DC_SSID,0);
-         fSteering->AddIntPar(PRINTSECTOR,1,-1);
-         fSteering->AddIntPar(HWMODESS_TSP,1,-1);
-         fSteering->AddIntPar(HWMODESS_DC,1,-1);
+      if(!s_fsteering) {
+         s_fsteering=new MakeSmallBankSteering();
+         s_fsteering->AddIntPar(TOWER,1,-1);
+         s_fsteering->AddStringPar(PCACHEIN,0,"");
+         s_fsteering->AddStringPar(PCACHEOUT,1,"");
+         s_fsteering->AddStringPar(CCACHEIN,0,"");
+         s_fsteering->AddStringPar(CCACHEOUT,1,"");
+         s_fsteering->AddIntPar(MAXPATT,1,-1);
+         s_fsteering->AddIntPar(IBLMODE,1,1);
+         s_fsteering->AddStringPar(ROOTIN,1);
+         s_fsteering->AddStringPar(PMAP,1,"");
+         s_fsteering->AddStringPar(RMAP,1,"");
+         s_fsteering->AddStringPar(SSMAP,1,"");
+         s_fsteering->AddStringPar(MODULELUTPATH,1,"");
+         s_fsteering->AddStringPar(TSP_SSMAP,1,"");
+         s_fsteering->AddDoublePar(TSP_SSID,0);
+         s_fsteering->AddDoublePar(DC_SSID,0);
+         s_fsteering->AddIntPar(PRINTSECTOR,1,-1);
+         s_fsteering->AddIntPar(HWMODESS_TSP,1,2);
+         s_fsteering->AddIntPar(HWMODESS_DC,1,2);
       }
-      return fSteering;
+      return s_fsteering;
    }
    MakeSmallBankSteering(void) {
-      fPmap=0;
-      fRmap=0;
-      fSSmap=0;
-      fSSmap_tsp=0;
+      m_fPmap=0;
+      m_fRmap=0;
+      m_fSSmap=0;
+      m_fSSmap_tsp=0;
+   }
+   int GetNumCCachedBankFileIn(void) const {
+      return (*this)[CCACHEIN]->GetActualSize();
    }
-   const char *GetCCachedBankFileIn(void) const {
-      return *(*this)[CCACHEIN];
+   const char *GetCCachedBankFileIn(int ind) const {
+      return (*(*this)[CCACHEIN])[ind];
    }
-   const char *GetPCachedBankFileIn(void) const {
-      return *(*this)[PCACHEIN];
+   int GetNumPCachedBankFileIn(void) const {
+      return (*this)[PCACHEIN]->GetActualSize();
    }
-   const char *GetBinaryFileIn(void) const {
-      return *(*this)[BINARYIN];
+   const char *GetPCachedBankFileIn(int ind) const {
+      return (*(*this)[PCACHEIN])[ind];
    }
    const char *GetRootFileIn(void) const {
       return *(*this)[ROOTIN];
    }
-   const char *GetBinaryFileOut(void) const {
-      return *(*this)[BINARYOUT];
-   }
    const char *GetCCacheFileOut(void) const {
       return *(*this)[CCACHEOUT];
    }
    const char *GetPCacheFileOut(void) const {
       return *(*this)[PCACHEOUT];
    }
-   const int GetNSSIDdc(void) {
+   int GetNumSSIDdc(void) const {
       return (*this)[DC_SSID]->GetActualSize();
    }
-   const pair<int,int> GetSSIDdc(int i) {
+   const pair<int,int> GetSSIDdc(int i) const {
       double dSSID=(*(*this)[DC_SSID])[i];
       pair<int,int> r;
       r.first=(int)dSSID;
       r.second=(int)((dSSID-r.first)*10.+0.5);
       return r;
    }
-   int GetNSSIDtsp(void) {
+   int GetNumSSIDtsp(void) const {
       return (*this)[TSP_SSID]->GetActualSize();
    }
-   const pair<int,int> GetSSIDtsp(int i) {
+   const pair<int,int> GetSSIDtsp(int i) const {
+      /// floating point input:  SSID.layer
       double dSSID=(*(*this)[TSP_SSID])[i];
       pair<int,int> r;
       r.first=(int)dSSID;
       r.second=(int)((dSSID-r.first)*10.+0.5);
       return r;
    }
-   int GetTower(void) {
+   int GetTower(void) const {
       return (*this)[TOWER][0];
    }
-   int GetPrintSector(void) {
+   int GetPrintSector(void) const {
       return (*this)[PRINTSECTOR][0];
    }
-   int GetMaxPatt(void) {
+   int GetMaxPatt(void) const {
       return (*this)[MAXPATT][0];
    }
-   int GetHWModeSS_tsp(void) {
+   int GetHWModeSS_tsp(void) const {
       return (*this)[HWMODESS_TSP][0];
    }
-   int GetHWModeSS_dc(void) {
+   int GetHWModeSS_dc(void) const {
       return (*this)[HWMODESS_DC][0];
    }
+   int GetIBLMODE(void) const {
+      return (*this)[IBLMODE][0];
+   }
    
    FTKSSMap *GetSSmap(void);
    FTKSSMap *GetSSmapTSP(void);
 private:
-   static MakeSmallBankSteering *fSteering;
+   static MakeSmallBankSteering *s_fsteering;
    void LoadPmapRmap(void);
 
-   FTKPlaneMap *fPmap;
-   FTKRegionMap *fRmap;
-   FTKSSMap *fSSmap;
-   FTKSSMap *fSSmap_tsp;
+   FTKPlaneMap *m_fPmap;
+   FTKRegionMap *m_fRmap;
+   FTKSSMap *m_fSSmap;
+   FTKSSMap *m_fSSmap_tsp;
 };
 
-MakeSmallBankSteering *MakeSmallBankSteering::fSteering=0;
+MakeSmallBankSteering *MakeSmallBankSteering::s_fsteering=0;
 
 int main(int argc, char const *argv[]) {
    // ============ read steering ==================
@@ -214,6 +206,9 @@ int main(int argc, char const *argv[]) {
          logging.Fatal("parse")<<"failed to open steering file \""
                                <<argv[1]<<"\"\n";
          error=3;
+      } else {
+         logging.Info("parse")<<"opened steering file \""
+                              <<argv[1]<<"\"\n";
       }
    }
    if(MakeSmallBankSteering::Instance()->Parse(*steering)<0) {
@@ -232,115 +227,121 @@ int main(int argc, char const *argv[]) {
    int hwModeSS_tsp=MakeSmallBankSteering::Instance()->GetHWModeSS_tsp();
    int hwModeSS_dc=MakeSmallBankSteering::Instance()->GetHWModeSS_dc();
 
-   char const *pcachedBankFileIn=
-      MakeSmallBankSteering::Instance()->GetPCachedBankFileIn();
-   FTK_CompressedAMBank *bank[4]={0,0,0,0};
-   int nBank=0;
+   vector<FTK_CompressedAMBank *> banks;
+   FTKSetup &ftkset = FTKSetup::getFTKSetup();
+   ftkset.setHWModeSS(2);
+   ftkset.setIBLMode(MakeSmallBankSteering::Instance()->GetIBLMODE());
+   ftkset.setITkMode(0);
+
    FTKSSMap *ssMap=MakeSmallBankSteering::Instance()->GetSSmap();
    FTKSSMap *ssMapTSP=MakeSmallBankSteering::Instance()->GetSSmapTSP();
-   if((!error)&& pcachedBankFileIn && pcachedBankFileIn[0]) {
-      bank[nBank]=new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
-                                           hwModeSS_tsp,hwModeSS_dc);
-      error=bank[nBank++]->readROOTBankCache(pcachedBankFileIn);
-   }
-   char const *ccachedBankFileIn=
-      MakeSmallBankSteering::Instance()->GetCCachedBankFileIn();
-   if((!error)&& ccachedBankFileIn && ccachedBankFileIn[0]) {
-      bank[nBank]=new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
-                                           hwModeSS_tsp,hwModeSS_dc);
-      error=bank[nBank++]->readROOTBankCache(ccachedBankFileIn);
-   }
-   char const *binaryInputName=
-     MakeSmallBankSteering::Instance()->GetBinaryFileIn();
-   if((!error) && binaryInputName && binaryInputName[0]) {
-      bank[nBank]=new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
-                                           hwModeSS_tsp,hwModeSS_dc);
-     error=bank[nBank++]->readBinaryFile(binaryInputName);
+   for(int ibank=0;
+       ibank<MakeSmallBankSteering::Instance()->GetNumPCachedBankFileIn();
+       ibank++) {
+      if(error) break;
+      FTK_CompressedAMBank *bank=
+         new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
+                                  hwModeSS_tsp,hwModeSS_dc);
+      bank->setCompressionScheme(FTK_CompressedAMBank::COMPRESSION_DELTA);
+      TDirectory *pcacheFile=FTKRootFile::Instance()->OpenRootFileReadonly
+         (MakeSmallBankSteering::Instance()->GetPCachedBankFileIn(ibank));
+      if(pcacheFile) {
+         error=bank->readPCachedBank(pcacheFile,0);
+         banks.push_back(bank);
+         delete pcacheFile;
+      } else {
+         logging.Error("pcache")
+            <<"could not open "
+            <<MakeSmallBankSteering::Instance()->GetPCachedBankFileIn(ibank)
+            <<"\n";
+         delete bank;
+      }
+   }
+   for(int ibank=0;
+       ibank<MakeSmallBankSteering::Instance()->GetNumCCachedBankFileIn();
+       ibank++) {
+      if(error) break;
+      FTK_CompressedAMBank *bank=
+         new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
+                                  hwModeSS_tsp,hwModeSS_dc);
+      bank->setCompressionScheme(FTK_CompressedAMBank::COMPRESSION_DELTA);
+      error=bank->readROOTBankCache
+         (MakeSmallBankSteering::Instance()->GetCCachedBankFileIn(ibank));
+      banks.push_back(bank);
    }
    char const *rootInputName=
      MakeSmallBankSteering::Instance()->GetRootFileIn();
    int maxPatterns=MakeSmallBankSteering::Instance()->GetMaxPatt();
    if((!error) && rootInputName && rootInputName[0]) {
-      bank[nBank]=new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
-                                           hwModeSS_tsp,hwModeSS_dc);
-      error=bank[nBank++]->readROOTBank(rootInputName,maxPatterns);
-   }
-   for(int iBank=1;iBank<nBank;iBank++) {
-     error=bank[0]->compare(bank[iBank]);
+      FTK_CompressedAMBank *bank=
+         new FTK_CompressedAMBank(tower,0,ssMap,ssMapTSP,
+                                  hwModeSS_tsp,hwModeSS_dc);
+      bank->setCompressionScheme(FTK_CompressedAMBank::COMPRESSION_DELTA);
+      error=bank->readROOTBank(rootInputName,maxPatterns);
+      banks.push_back(bank);
+   }
+   for(size_t iBank=1;iBank<banks.size();iBank++) {
+     error=banks[0]->compare(banks[iBank]);
      if(error) {
         logging.Error("main")<<"bank[0] and bank["
                              <<iBank<<"] are not in agreement\n";
+     } else {
+        logging.Info("main")<<"bank[0] and bank["
+                            <<iBank<<"] are in agreement\n";
      }
    }
-   char const *binaryOutputName=
-      MakeSmallBankSteering::Instance()->GetBinaryFileOut();
-   if((!error) && bank[0] && binaryOutputName && binaryOutputName[0]) {
-      error=bank[0]->writeBinaryFile(binaryOutputName);
-   }
    char const *ccachedBankOutputName=
       MakeSmallBankSteering::Instance()->GetCCacheFileOut();
-   if((!error) && bank[0] && ccachedBankOutputName &&
+   if((!error) && banks[0] && ccachedBankOutputName &&
       ccachedBankOutputName[0]) {
-      error=bank[0]->writeCCachedBankFile(ccachedBankOutputName);
+      error=banks[0]->writeCCachedBankFile(ccachedBankOutputName);
    }
    char const *pcachedBankOutputName=
       MakeSmallBankSteering::Instance()->GetPCacheFileOut();
-   if((!error) && bank[0] && pcachedBankOutputName && 
+   if((!error) && banks[0] && pcachedBankOutputName && 
       pcachedBankOutputName[0]) {
-      error=bank[0]->writePCachedBankFile(pcachedBankOutputName);
+      error=banks[0]->writePCachedBankFile(pcachedBankOutputName);
    }
 
-   if((!error) && bank[0]) {
-#ifdef USE_COMPRESSEDAMBANK_DC
-      std::vector<FTK_CompressedAMBank>
-#else
-         std::vector<std::list<int> >
-#endif
-         roadFinderInput(bank[0]->getNPlanes());
-      for(int i=0;i<MakeSmallBankSteering::Instance()->GetNSSIDdc();i++) {
+   if((!error) && banks[0]) {
+      FTK_CompressedAMBank *bank=banks[0];
+      std::vector<std::list<int> > roadFinderInput(bank->getNPlanes());
+      for(int i=0;i<MakeSmallBankSteering::Instance()->GetNumSSIDdc();i++) {
          pair<int,int> dcSSIDlayer=
             MakeSmallBankSteering::Instance()->GetSSIDdc(i);
          int layer=dcSSIDlayer.second;
          int dcSSID=dcSSIDlayer.first;
          cout<<i<<" L="<<layer<<" dcSSID="<<dcSSID<<" -> tspSSID=[";
-         vector<int> tspSSIDvector=bank[0]->getTSPssidVector(layer,dcSSID);
+         vector<int> tspSSIDvector=bank->getTSPssidVector(layer,dcSSID);
          for(unsigned j=0;j<tspSSIDvector.size();j++) {
             cout<<" "<<tspSSIDvector[j];
          }
          cout<<"]\n";
-#ifdef USE_COMPRESSEDAMBANK_DC
-         roadFinderInput[layer][dcSSID]=(1<<tspSSIDvector.size())-1;
-#else
          for(unsigned j=0;j<tspSSIDvector.size();j++) {
             roadFinderInput[layer].push_back(tspSSIDvector[j]);
          }
-#endif
       }
-      for(int i=0;i<MakeSmallBankSteering::Instance()->GetNSSIDtsp();i++) {
+      for(int i=0;i<MakeSmallBankSteering::Instance()->GetNumSSIDtsp();i++) {
          pair<int,int> tspSSIDlayer=
             MakeSmallBankSteering::Instance()->GetSSIDtsp(i);
          int layer=tspSSIDlayer.second;
          int tspSSID=tspSSIDlayer.first;
-         std::pair<int,int> dcSSIDxy=bank[0]->getDCssid(layer,tspSSID);
+         std::pair<int,int> dcSSIDxy=bank->getDCssid(layer,tspSSID);
          cout<<"L="<<layer<<" tspSSID "<<tspSSID<<" -> dcSSID="<<dcSSIDxy.first
              <<" tspLOCAL="<<dcSSIDxy.second<<"\n";
-#ifdef USE_COMPRESSEDAMBANK_DC
-         roadFinderInput[layer][dcSSIDxy.first] |= 1<<dcSSIDxy.second;
-#else
          roadFinderInput[layer].push_back(tspSSID);
-#endif
       }
-      bank[0]->init();
-      bank[0]->clear();
-      bank[0]->data_organizer_r(roadFinderInput);
-      bank[0]->am_in_r(roadFinderInput);
-      bank[0]->am_output();
-      bank[0]->printRoads(bank[0]->getRoads(),-1);
-   }
-   if((!error) && bank[0]) {
+      bank->init();
+      bank->clear();
+      bank->data_organizer_r(roadFinderInput);
+      bank->am_in_r(roadFinderInput);
+      bank->am_output();
+      bank->printRoads(bank->getRoads(),-1);
+   }
+   if((!error) && banks[0]) {
       int printsector=MakeSmallBankSteering::Instance()->GetPrintSector();
       if(printsector>=0) {
-         bank[0]->printSector(printsector);
+         banks[0]->printSector(printsector);
       }
    }
 
@@ -348,26 +349,29 @@ int main(int argc, char const *argv[]) {
 }
 
 void MakeSmallBankSteering::LoadPmapRmap(void) {
-  if(!fPmap) {
-      fPmap = new FTKPlaneMap(*(*this)[PMAP]);
+  if(!m_fPmap) {
+      m_fPmap = new FTKPlaneMap(*(*this)[PMAP]);
+   }
+   if(!m_fRmap) {
+      m_fRmap = new FTKRegionMap(m_fPmap,*(*this)[RMAP]);
    }
-   if(!fRmap) {
-      fRmap = new FTKRegionMap(fPmap,*(*this)[RMAP]);
+   if((GetHWModeSS_tsp()==2)||(GetHWModeSS_dc()==2)) {
+      m_fRmap->loadModuleIDLUT(*(*this)[MODULELUTPATH]);
    }
 }
 
 FTKSSMap *MakeSmallBankSteering::GetSSmap(void) {
    LoadPmapRmap();
-   if(!fSSmap) {
-      fSSmap=new FTKSSMap(fRmap,*(*this)[SSMAP],false); // FTKRoadFinderAlgo
+   if(!m_fSSmap) {
+      m_fSSmap=new FTKSSMap(m_fRmap,*(*this)[SSMAP],false); // FTKRoadFinderAlgo
    }
-   return fSSmap;
+   return m_fSSmap;
 }
 
 FTKSSMap *MakeSmallBankSteering::GetSSmapTSP(void) {
    LoadPmapRmap();
-   if(!fSSmap_tsp) {
-      fSSmap_tsp=new FTKSSMap(fRmap,*(*this)[TSP_SSMAP],false);// FTKRoadFinderAlgo
+   if(!m_fSSmap_tsp) {
+      m_fSSmap_tsp=new FTKSSMap(m_fRmap,*(*this)[TSP_SSMAP],false);// FTKRoadFinderAlgo
    }
-   return fSSmap_tsp;
+   return m_fSSmap_tsp;
 }
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/partitionbalancing.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/partitionbalancing.cc
index c57396ac8b87..75d125a769cd 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/partitionbalancing.cc
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/partitionbalancing.cc
@@ -44,30 +44,34 @@ using namespace std;
 class PartitionSteering : public FTKSteering {
 public:
    static PartitionSteering *Instance(void) {
-      if(!m_steering) {
-         m_steering=new PartitionSteering();
+      if(!s_fsteering) {
+         s_fsteering=new PartitionSteering();
 
-         m_steering->AddIntPar("NREG",1,0);
-         m_steering->AddIntPar("NSUB",1,0);
-         m_steering->AddIntPar("NPATTERN",1,0);
+         s_fsteering->AddIntPar("NREG",1,0);
+         s_fsteering->AddIntPar("NSUB",1,0);
+         s_fsteering->AddIntPar("NPATTERN",1,0);
 
-         m_steering->AddIntPar("maxSectorId",1,0);
+         s_fsteering->AddIntPar("maxSectorId",1,0);
+         s_fsteering->AddIntPar("rebinSlices",1,0);
 
-         m_steering->AddDoublePar("absetarange",2,0.0);
+         s_fsteering->AddDoublePar("absetarange",2,0.0);
 
-         m_steering->AddDoublePar("etabinOffset",1,0.0);
+         s_fsteering->AddDoublePar("etabinOffset",1,0.0);
 
-         m_steering->AddDoublePar("epsilonLimit",1,1.0);
-         m_steering->AddDoublePar("weightLimit",1,0.0);
+         s_fsteering->AddDoublePar("epsilonLimit",1,1.0);
+         s_fsteering->AddDoublePar("weightLimit",1,0.0);
 
-         m_steering->AddStringPar("efficiency_file");
-         m_steering->AddStringPar("efficiency_plot");
+         s_fsteering->AddStringPar("efficiency_file");
+         s_fsteering->AddStringPar("efficiency_plot");
 
-         m_steering->AddStringPar("pattern_bank_path");
-         m_steering->AddStringPar("slices_file_path");
+         s_fsteering->AddStringPar("pattern_bank_path");
+         s_fsteering->AddStringPar("slices_file_path");
+
+         s_fsteering->AddStringPar("maximum_input_file");
+         s_fsteering->AddStringPar("maximum_output_file");
 
       }
-      return m_steering;
+      return s_fsteering;
    }
    const char *GetEfficiencyFileName(void) const {
       return *(*this)["efficiency_file"];
@@ -81,6 +85,12 @@ public:
    const char *GetSlicesFilePath(void) const {
       return *(*this)["slices_file_path"];
    }
+   const char *GetMaximumInputFile(void) const {
+      return *(*this)["maximum_input_file"];
+   }
+   const char *GetMaximumOutputFile(void) const {
+      return *(*this)["maximum_output_file"];
+   }
    double GetAbsEtaRangePar(int i) const {
       return (*(*this)["absetarange"])[i];
    }
@@ -96,6 +106,9 @@ public:
    int GetMaxSectorId(void) const {
       return (*this)["maxSectorId"][0];
    }
+   int GetRebinSlices(void) const {
+      return (*this)["rebinSlices"][0];
+   }
    int GetNPattern(void) const {
       return (*this)["NPATTERN"][0];
    }
@@ -106,10 +119,10 @@ public:
       return (*this)["NREG"][0];
    }
 protected:
-   static PartitionSteering *m_steering;
+   static PartitionSteering *s_fsteering;
 };
 
-PartitionSteering *PartitionSteering::m_steering=0;
+PartitionSteering *PartitionSteering::s_fsteering=0;
 
 int main(int argc, char const *argv[]) {
    // ============ read steering ==================
@@ -173,6 +186,9 @@ int main(int argc, char const *argv[]) {
    // this is a limit on the maximum allowed sector ID
    //   -> sectorIDs >= max will not be written to the partition file
    int maxSectorId=PartitionSteering::Instance()->GetMaxSectorId();
+   //
+   // this combines several half-slices into one bin
+   int rebinSlices=PartitionSteering::Instance()->GetRebinSlices();
 
    cout<<"abs(eta) range: "<<absetamin<<"..."<<absetamax<<"\n";
    cout<<"etabinOffset: "<<etabinOffset<<"\n";
@@ -189,8 +205,46 @@ int main(int argc, char const *argv[]) {
    TH2D *originalPerSlice2(0),*partitionedPerSlice2(0);
    TH1D *etaPerSlice2(0),*cosThetaPerSlice2(0);
 
+   vector<map<int,int> > knownMax(nreg);
+   char const *maximumInputFile=PartitionSteering::Instance()->GetMaximumInputFile();
+   if(maximumInputFile) {
+      ifstream in(maximumInputFile);
+      int line=1;
+      while(!in.eof()) {
+         int ireg,sector,maximum;
+         in>>ireg>>sector>>maximum;
+         if(in.fail()) break;
+         if((ireg<0)||(ireg>=(int)knownMax.size())) {
+            logging.Error("maximumFromFile")<<"bad region="<<ireg<<" at line="<<line<<"\n";
+            break;
+         }
+         if(knownMax[ireg].find(sector)!=knownMax[ireg].end()) {
+            logging.Error("maximumFromFile")<<"duplicate sector="<<sector<<" in region="<<ireg<<" at line="<<line<<"\n";
+            break;
+         }
+         if(maximum<=0) {
+            logging.Error("maximumFromFile")<<"max maximum="<<maximum<<" in sector="<<sector<<" region="<<ireg<<" at line="<<line<<"\n";
+            break;
+         }
+         knownMax[ireg][sector]=maximum;
+         line++;
+      }
+   }
+
+   ofstream *dumpMaximum=0;
+   char const *maximumOutputFile= PartitionSteering::Instance()->GetMaximumOutputFile();
+   if(maximumOutputFile) {
+      dumpMaximum=new ofstream(maximumOutputFile);
+   }
+
    for(int reg=0;reg<nreg;reg++) {
-      logging.Info("loop")<<"Processing region "<<reg<<"\n";
+
+      struct SectorPatternData {
+         int fNPattern;
+         int fNMax;
+      };
+
+      logging.Info("loop")<<"Processing region "<<reg<<" known max for "<<knownMax[reg].size()<<" sector(s)\n";
       // read slices
       TString sliceFileName=
          PartitionSteering::Instance()->GetSlicesFilePath()+
@@ -201,7 +255,7 @@ int main(int argc, char const *argv[]) {
          // ctheta contains for each slice in cos(theta) a bitvector
          //  the bits correspond to sector IDs
          //  if the bit is on, the sector may have patterns
-         //  in teh given cos(theta) bin
+         //  in the given cos(theta) bin
          TClonesArray *ctheta;
          TString name("c_bits_ctheta");
          slices->GetObject(name,ctheta);
@@ -218,12 +272,16 @@ int main(int argc, char const *argv[]) {
          // either read one subregion or read nSub subregions
 
          // this variable will contain the number of patterns per sector
-         map<int,int> patternsPerSector;
+         //   first : patterns per sector
+         //   second :  1 if at limit, -1 or 0 otherwise
+         map<int,SectorPatternData> patternsPerSector;
+
          // this variable will contain the total number of patterns
          int nPatternRead=0;
          for(int isubRead=0;isubRead<nsub;isubRead++) {
             // read pattern bank(s) and determine number of patterns
             //   per sector
+            int nPatternSub=0;
             TString bankName=
                PartitionSteering::Instance()->GetPatternBankPath()+
                TString::Format("/*_reg%d_sub%d.p*.root",reg,isubRead);
@@ -266,46 +324,104 @@ int main(int argc, char const *argv[]) {
             //
             // count sector multiplicities
             // for the given bank, read the sectorID of all patterns
-            // and cout the (original) number of patterns per sector ID
+            // and count the (original) number of patterns per sector ID
             TTree *tree;
-            patternBank->GetObject("Bank",tree);
-            if(!tree) {
-               logging.Fatal("subregion")<<"can not find TTree \"Bank\"\n";
-            }
-            int nPattern=tree->GetEntriesFast();
-            FTKPattern *pattern=new FTKPattern();
-            if(tree->SetBranchAddress("Pattern",&pattern)!=0) {
-               // no match, assume this is a flat file
-               logging.Info("subregion")<<"try to read flat format\n";
-               delete pattern;
-               pattern=0;
-            }
-            TBranch *branch_sectorID=0;
-            int sectorID;
-            if(!pattern) {
-               // flat format
-               // access branches and set addresses
-               branch_sectorID=tree->GetBranch("sectorID");
-               branch_sectorID->SetAddress(&sectorID);
+            patternBank->GetObject("Sector",tree);
+            if(tree) {
+               int sector,first,last,allPatternsUsed;
+               tree->SetBranchAddress("sector",&sector);
+               tree->SetBranchAddress("first",&first);
+               tree->SetBranchAddress("last",&last);
+               tree->SetBranchAddress("allPatternsUsed",&allPatternsUsed);
+               for(int i=0;i<tree->GetEntries();i++) {
+                  allPatternsUsed=0;
+                  tree->GetEntry(i);
+                  int n=last+1-first;
+                  for(int special=((first-1) & 0xfffe0000)+0x20000;special<=last;special += 0x20000) {
+                     n--; // special patterns are not counted
+                  }
+                  SectorPatternData &pps=patternsPerSector[sector];
+                  pps.fNPattern = n;
+                  pps.fNMax = (allPatternsUsed==1) ? n : PartitionSteering::Instance()->GetNPattern();
+                  nPatternSub+=n;                  
+               }
             } else {
-               branch_sectorID=tree->GetBranch("m_sectorID");
-            }
-            for(int iPattern=0;iPattern<nPattern;++iPattern) {
-               branch_sectorID->GetEntry(iPattern);
-               if(pattern) {
-		 sectorID=pattern->getSectorID();
+               patternBank->GetObject("Bank",tree);
+               if(!tree) {
+                  logging.Fatal("subregion")<<"can not find TTree \"Bank\"\n";
+               }
+               int nPattern=tree->GetEntriesFast();
+               FTKPattern *pattern=new FTKPattern();
+               if(tree->SetBranchAddress("Pattern",&pattern)!=0) {
+                  // no match, assume this is a flat file
+                  logging.Info("subregion")<<"try to read flat format\n";
+                  delete pattern;
+                  pattern=0;
+               }
+               TBranch *branch_sectorID=0;
+               int sectorID;
+               if(!pattern) {
+                  // flat format
+                  // access branches and set addresses
+                  branch_sectorID=tree->GetBranch("sectorID");
+                  branch_sectorID->SetAddress(&sectorID);
+               } else {
+                  branch_sectorID=tree->GetBranch("m_sectorID");
+               }
+               for(int iPattern=0;iPattern<nPattern;++iPattern) {
+                  branch_sectorID->GetEntry(iPattern);
+                  if(pattern) {
+                     sectorID=pattern->getSectorID();
+                  }
+                  patternsPerSector[sectorID].fNPattern++;
+                  patternsPerSector[sectorID].fNMax=PartitionSteering::Instance()->GetNPattern();
+                  nPatternSub++;
                }
-               patternsPerSector[sectorID]++;
-               nPatternRead++;
             }
             globfree(&globStruct);
             logging.Info("subregion")
-               <<"read subregion="<<isubRead<<" nPattern="<<nPattern<<"\n";
+               <<"read subregion="<<isubRead<<" nPattern="<<nPatternSub<<"\n";
+            nPatternRead += nPatternSub;
          }
          logging.Info("readpattern")
             <<"total sectors (bank): "<<patternsPerSector.size()
             <<" total patterns: "<<nPatternRead<<"\n";
 
+         // add information abount known maxima
+         for(map<int,int>::const_iterator i=knownMax[reg].begin();
+             i!=knownMax[reg].end();i++) {
+            map<int,SectorPatternData>::iterator
+               i2=patternsPerSector.find((*i).first);
+            if(i2==patternsPerSector.end()) {
+               SectorPatternData &pps=patternsPerSector[(*i).first];
+               pps.fNPattern=0;
+               pps.fNMax=(*i).second;
+            } else if((*i2).second.fNMax==
+                      PartitionSteering::Instance()->GetNPattern()) {
+               logging.Info("setMaximum")
+                  <<"reg="<<reg<<" sector="<<(*i2).first
+                  <<" fMax "<<(*i2).second.fNMax
+                  <<" -> "<<(*i).second<<"\n";
+               (*i2).second.fNMax=(*i).second;
+            } else if((*i2).second.fNMax!=(*i).second) {
+               logging.Error("setMaximum")
+                  <<"reg="<<reg<<" sector="<<(*i2).first
+                  <<" fMax="<<(*i2).second.fNMax
+                  <<" fMax(iteration-1)="<<(*i).second<<"\n";
+            }
+         }
+
+         // dump information about maximum per sector
+         if(dumpMaximum) {
+            for(map<int,SectorPatternData>::const_iterator i=patternsPerSector.begin();
+                i!=patternsPerSector.end();i++) {
+               if((*i).second.fNMax<
+                  PartitionSteering::Instance()->GetNPattern()) {
+                  (*dumpMaximum)<<reg<<" "<<(*i).first
+                                <<" "<<(*i).second.fNMax<<"\n";
+               }
+            }
+         }
 
          // here we have:
          //  ctheta[] : sectors per cos(theta) slice
@@ -353,49 +469,73 @@ int main(int argc, char const *argv[]) {
             // This sets the number of partitions along eta
             //   there is one partition for each possible half-integer number
             //   empty partitions will be skipped.
-            int nSlice2=2*nSlice1;
+
+            int nSliceTimes2=2*nSlice1;
+            int nSliceRebin=nSliceTimes2/(rebinSlices>0 ? rebinSlices : 1);
+            if((rebinSlices>0)&&(nSliceTimes2 % rebinSlices)) {
+               nSliceRebin++;
+            }
 
             if(!originalPerSlice2) {
                outputRoot->cd();
                originalPerSlice2=new TH2D("originalPerSlice2",
                                            ";slice;tower",
-                                           nSlice2,-0.5,nSlice2-0.5,
+                                           nSliceRebin,-0.5,nSliceRebin-0.5,
                                            nreg,-0.5,nreg-0.5);
                partitionedPerSlice2=new TH2D("partitionedPerSlice2",
                                               ";slice;tower",
-                                              nSlice2,-0.5,nSlice2-0.5,
+                                              nSliceRebin,-0.5,nSliceRebin-0.5,
                                               nreg,-0.5,nreg-0.5);
                etaPerSlice2=new TH1D("etaPerSlice2",";slice;eta",
-                                     nSlice2,-0.5,nSlice2-0.5);
+                                     nSliceRebin,-0.5,nSliceRebin-0.5);
                cosThetaPerSlice2=new TH1D("cosThetaPerSlice2",
                                           ";slice;cos(theta)",
-                                          nSlice2,-0.5,nSlice2-0.5);
+                                          nSliceRebin,-0.5,nSliceRebin-0.5);
             }
             // next, each sector is assigned to one partition "nslice2"
-            vector<int> patternPerSlice(nSlice2);
-            vector<vector<int> > sectorList(nSlice2);
+            // first : number of patterns
+            // second : if zero, all sectors are at limit
+            vector<SectorPatternData > patternPerSlice(nSliceRebin);
+            vector<vector<int> > sectorList(nSliceRebin);
             for(map<int,double>::const_iterator is=sum0.begin();
               is!=sum0.end();is++) {
                int sector=(*is).first;
-               int slice2=(int)(2.*sum1[sector]/(*is).second);
+               int sliceRebin=
+                  ((int)(2.*sum1[sector]/(*is).second))/
+                  (rebinSlices>0 ? rebinSlices : 0);
+               if(sliceRebin>=nSliceRebin) sliceRebin=nSliceRebin-1;
                //sliceNumber[sector]=slice;
-               sectorList[slice2].push_back(sector);
+               sectorList[sliceRebin].push_back(sector);
                if(patternsPerSector.find(sector)!=patternsPerSector.end()) {
-                  patternPerSlice[slice2]+=patternsPerSector[sector];
+                  SectorPatternData &ppSlice=patternPerSlice[sliceRebin];
+                  SectorPatternData &ppSector=patternsPerSector[sector];
+                  ppSlice.fNPattern += ppSector.fNPattern;
+                  ppSlice.fNMax += ppSector.fNMax;
+                  if(ppSlice.fNMax>PartitionSteering::Instance()->GetNPattern()) {
+                     ppSlice.fNMax=PartitionSteering::Instance()->GetNPattern();
+                  }
+               }
+            }
+            for(int i=0;i<nSliceRebin;i++) {
+               if((patternPerSlice[i].fNMax>0)&&(patternPerSlice[i].fNMax<PartitionSteering::Instance()->GetNPattern())) {
+                  logging.Info("Truncation")<<"isub="<<isub<<" islice="<<i<<" nmax="<<patternPerSlice[i].fNMax
+                                            <<" npattern="<<patternPerSlice[i].fNPattern<<"\n";
                }
             }
             // here:
             //   sectorList[partition][] :  the sectors in this partition 
-            //   patternPerSlice[partition] : number of patterns in partition
+            //   patternPerSlice[partition]
+            //     : number of patterns and maximum in partition
 
             // (2) for each slice determine the efficiency and add up
             //   the target number of patterns
-            vector<double> targetPatterns(nSlice2);
+            vector<double> targetPatterns(nSliceRebin);
             double ctheta0=TMath::SinH(-3.),ctheta1=TMath::SinH(3.);
             double total=0.;
-            for(int i=0;i<nSlice2;i++) {
+            for(int i2=0;i2<nSliceTimes2;i2++) {
                // get cos(theta) from slice number
-               double ctheta=(i+etabinOffset)*(ctheta1-ctheta0)/nSlice2+ctheta0;
+               double ctheta=(i2+etabinOffset)*(ctheta1-ctheta0)/
+                  nSliceTimes2+ctheta0;
                // get eta coordinate (for efficiency plot)
                double eta=TMath::ASinH(ctheta);
                double abseta=TMath::Abs(eta);
@@ -403,11 +543,13 @@ int main(int argc, char const *argv[]) {
                double epsilon=efficiencyPlot->Eval(eta);
                double epsilon0=
                   PartitionSteering::Instance()->GetEpsilonLimit();
+               int i=i2/(rebinSlices>0 ? rebinSlices : 1);
+               if(i>=nSliceRebin) i=nSliceRebin-1;
                cosThetaPerSlice2->SetBinContent(i+1,ctheta);
                etaPerSlice2->SetBinContent(i+1,eta);
                if(((absetamin>=absetamax)||
                    ((abseta>=absetamin)&&(abseta<=absetamax)))&&
-                  (patternPerSlice[i]>0)) {
+                  (patternPerSlice[i].fNPattern>0)) {
                   double weight=PartitionSteering::Instance()
                      ->GetWeightLimit();
                   if(epsilon<epsilon0) {
@@ -417,26 +559,23 @@ int main(int argc, char const *argv[]) {
                         weight=PartitionSteering::Instance()->GetWeightLimit();
                      }
                   }
-                  // weight: desired weighting factor fro which the predicted
+                  // weight: desired weighting factor for which the predicted
                   //   efficiency reaches the target efficiency
 
-                  targetPatterns[i]+= patternPerSlice[i]*weight;
+                  targetPatterns[i]+= patternPerSlice[i].fNPattern*weight;
                   total+= targetPatterns[i];
                }
-               originalPerSlice2->SetBinContent(i+1,reg+1,patternPerSlice[i]);
+               originalPerSlice2->SetBinContent
+                  (i+1,reg+1,patternPerSlice[i].fNPattern);
             }
             // here:
             //   targetPatterns[partition] : patterns needed to reach target
             //                                 efficiency
             //   total : total number of patterns needed to reach target
 
-            // (3) normalize and round
+            // (3) normalize
             //   targetPatterns[] should be scaled down by the factor
             //     nPattern/total 
-            //  Problem: finally, all number have to be integer
-            //    fractional patterns have to be rounded up or down
-            //
-            int tot=0;
             // target number of patterns in this subregion
             int nPattern=nPatternRead/nsub;
             if(PartitionSteering::Instance()->GetNPattern())
@@ -444,53 +583,105 @@ int main(int argc, char const *argv[]) {
             if(total==0) {
                logging.Warning("subregion")
                   <<"no sectors accepted, store one pattern per partition\n";
-               nPattern=nSlice2;
+               nPattern=nSliceTimes2;
+            }
+            for(int i=0;i<nSliceRebin;i++) {
+               targetPatterns[i]*=((double)nPattern)/total;
             }
-            for(int i=0;i<nSlice2;i++) {
+            // (4) take into account truncation
+            double truncate=0.;
+            do {
+               total=0.;
+               double free=0.;
+               truncate=0.;
+               for(int i=0;i<nSliceRebin;i++) {
+                  if(targetPatterns[i]>=patternPerSlice[i].fNMax) {
+                     truncate += targetPatterns[i]-patternPerSlice[i].fNMax;
+                     if(targetPatterns[i]>0.0) {
+                        logging.Info("target")<<" slice="<<i<<" change from "<<targetPatterns[i]<<" to "<<patternPerSlice[i].fNMax<<"\n";
+                     }
+                     targetPatterns[i]=patternPerSlice[i].fNMax;
+                  } else {
+                     free+=targetPatterns[i];
+                  }
+                  total+=targetPatterns[i];
+               }
+               logging.Info("target")<<" total="<<total<<" nPattern="<<nPattern<<" free="<<free<<" truncate="<<truncate<<"\n";
+               if(free<=0.) break;
+               // truncate: excess patterns to be distributed
+               double scale=truncate/free;
+               for(int i=0;i<nSliceRebin;i++) {
+                  if(targetPatterns[i]<patternPerSlice[i].fNMax-0.5) {
+                     double n=targetPatterns[i]*scale;
+                     targetPatterns[i] += n;
+                     truncate -= n;
+                  }
+               }
+            } while(truncate>1.0);
+
+            //  (5) finally, all numbers have to be integer
+            //    fractional patterns have to be rounded up or down
+            //    also, take into account truncation
+
+            // round to integer
+            int tot=0;
+            for(int i=0;i<nSliceRebin;i++) {
                // skip empty partitions
-               if(patternPerSlice[i]==0) continue;
+               if(patternPerSlice[i].fNPattern==0) continue;
                if(total>0) {
-                  // normalized targen number of patterns
-                  patternPerSlice[i]=
-                     (int)((targetPatterns[i]*nPattern)/total+0.5);
+                  int target=(int)(targetPatterns[i]+0.5);
+                  if(patternPerSlice[i].fNMax>target) {
+                     // set new normalized target number of patterns
+                     // (only for those partitions which are not at limit)
+                     patternPerSlice[i].fNPattern=target;
+                  } else {
+                     patternPerSlice[i].fNPattern=patternPerSlice[i].fNMax;
+                  }
+                  tot+= patternPerSlice[i].fNPattern;
                } else {
-                  patternPerSlice[i]=1;
+                  patternPerSlice[i].fNPattern=1;
                }
-               tot+= patternPerSlice[i];
             }
-            // here:
-            //  patternPerSlice[i] : renormalized target number of patterns
-            //                         integer
-            //                  !!! the original content is overwritten !!!
-            //  tot : sum of renormalizerd target number of patterns
-
-            // execute tis loop to adjust the number of patterns
+            logging.Info("adjust")<<"isub="<<isub<<" tot="<<tot<<" nPattern="<<nPattern<<"\n";
+            // execute this loop to adjust the number of patterns
             //   until the integer number: tot
             //   equals the target number: nPattern
+            int nAdjustTotal=0;
+            int nLimitTotal=0;
             while(tot-nPattern) {
                // try all partitions in sequence
-               for(int i=0;i<nSlice2;i++) {
+               int nAdjust=0;
+               int nLimit=0;
+               for(int i=0;i<nSliceRebin;i++) {
                   // do not adjust empty partitions
-                  if(patternPerSlice[i]<=0) continue;
+                  if(patternPerSlice[i].fNPattern<=0) continue;
+                  // do not adjust partitions which are at limit
                   int delta=tot-nPattern;
                   if(!delta) break; // done
                   else if(delta>0) {
                      // too many patterns, subtract one in this partition
                      tot--;
-                     patternPerSlice[i]--;
+                     patternPerSlice[i].fNPattern--;
+                     nAdjust++;
                   } else if(delta<0) {
                      // too few patterns, add one in this partition
-                     // (the if is redundant???)
-                     if(patternPerSlice[i]>0) {
+                     if(patternPerSlice[i].fNPattern<patternPerSlice[i].fNMax) {
                         tot++;
-                        patternPerSlice[i]++;
+                        patternPerSlice[i].fNPattern++;
+                        nAdjust++;
+                     } else {
+                        nLimit++;
                      }
                   }
                }
+               nAdjustTotal+=nAdjust;
+               nLimitTotal+=nLimit;
+               if(nAdjust==0) break;
             }
-            for(int i=0;i<nSlice2;i++) {
-               partitionedPerSlice2->SetBinContent(i+1,reg+1,
-                                                   patternPerSlice[i]);
+            logging.Info("adjust")<<"total="<<tot<<" nPattern="<<nPattern<<" adjustTotal="<<nAdjustTotal<<" limit="<<nLimitTotal<<"\n";
+            for(int i=0;i<nSliceRebin;i++) {
+               partitionedPerSlice2->SetBinContent
+                  (i+1,reg+1,patternPerSlice[i].fNPattern);
             }
             // done
             // write out partition file
@@ -498,10 +689,11 @@ int main(int argc, char const *argv[]) {
             int nSectorUsed=0;
             int nSectorUsedBank=0;
             int nSliceUsed=0;
-            for(int i=0;i<nSlice2;i++) {
-               if(sectorList[i].size() && patternPerSlice[i]) {
-                  sum += patternPerSlice[i];
-                  (*outputFile)<<"PARTITION "<<iPart<<" "<<patternPerSlice[i]
+            for(int i=0;i<nSliceRebin;i++) {
+               if(sectorList[i].size() && patternPerSlice[i].fNPattern) {
+                  sum += patternPerSlice[i].fNPattern;
+                  (*outputFile)<<"PARTITION "<<iPart<<" "
+                               <<patternPerSlice[i].fNPattern
                                <<" "<<sectorList[i].size();
                   for(unsigned j=0;j<sectorList[i].size();j++) {
                      if(!j) (*outputFile)<<"\n";
@@ -516,6 +708,11 @@ int main(int argc, char const *argv[]) {
                   }
                   nSectorUsed+=sectorList[i].size();
                   (*outputFile)<<"\n";
+                  logging.Info("result")
+                     <<"ipart="<<iPart<<" isub="<<isub <<" islice="<<i
+                     <<" npattern="<<patternPerSlice[i].fNPattern
+                     <<" nmax="<<patternPerSlice[i].fNMax
+                     <<"\n";
                   iPart++;
                   nSliceUsed++;
                }
@@ -557,6 +754,9 @@ int main(int argc, char const *argv[]) {
    etaPerSlice2->Write();
    cosThetaPerSlice2->Write();
    delete outputRoot;
+
+   if(dumpMaximum) delete dumpMaximum;
+
    logging.Info("output")
       <<"maxSector="<<totalMaxSector<<" maxSectorUsed="<<totalMaxSectorUsed
       <<" nSectorTotal="<<totalNsectorTotal<<" nSectorUsed="<<totalNsectorUsed
diff --git a/Trigger/TrigFTK/TrigFTKSim/standalone/patternbankinfo.cc b/Trigger/TrigFTK/TrigFTKSim/standalone/patternbankinfo.cc
index 45aec91670d7..0a3845bcad73 100644
--- a/Trigger/TrigFTK/TrigFTKSim/standalone/patternbankinfo.cc
+++ b/Trigger/TrigFTK/TrigFTKSim/standalone/patternbankinfo.cc
@@ -30,8 +30,11 @@
 
 using namespace std;
 
+double HUFbytes(TH1D const *hist);
+
 int main(int argc, char const *argv[]) {
    FTKLogging logging("main");
+   FTKLogging::SetAbortLevel(1);
    std::string output;
    std::vector<std::string> files;
    try {
@@ -67,33 +70,41 @@ int main(int argc, char const *argv[]) {
    TDirectory *statFile=FTKRootFile::Instance()->
       CreateRootFile(output.c_str());
    std::map<int,uint64_t> s100sector,s100pattern,s1pattern;
+
+   // bank compression analysis
+   vector<int> nDataMax;
+
    int ifilesRead=0;
    for(unsigned ifile=0;ifile<files.size();ifile++) {
-      TDirectory *bankFile=FTKRootFile::Instance()->
-         OpenRootFileReadonly(files[ifile].c_str());
+      FTKRootFileChain fileChain;
+      fileChain.Open(files[ifile].c_str());
+      TDirectory *bankFile=fileChain.GetDirectory();
       if(!bankFile) {
          logging.Fatal("openInputFile")<<"can not open: "<<files[ifile]<<"\n";
       } else {
          logging.Info("openInputFile")<<"file opened: "<<files[ifile]<<"\n";
-         FTKPatternBySectorReader bankReader(*bankFile);
+         FTKPatternBySectorReader *bankReader=
+            FTKPatternBySectorReader::Factory(fileChain);
          int nSector=0;
-         for(int sector=bankReader.GetFirstSector();sector>=0;
-             sector=bankReader.GetNextSector(sector)) {
+         for(int sector=bankReader->GetFirstSector();sector>=0;
+             sector=bankReader->GetNextSector(sector)) {
             nSector++;
             int i100=sector/100;
             s100sector[i100]++;
-            uint64_t nPattern=bankReader.GetNPatterns(sector);
+            uint64_t nPattern=bankReader->GetNPatterns(sector);
             s100pattern[i100]+=nPattern;
             s1pattern[sector]+=nPattern;
          }
+         logging.Info("openInputFile")<<"nsector="<<nSector<<"\n";
          if(nSector) {
             logging.Info("sectorOrderedFile")
-               <<"total number of patterns: "<<bankReader.GetNPatterns()<<"\n";
+               <<"total number of patterns: "
+               <<bankReader->GetNPatternsTotal()<<"\n";
             logging.Info("sectorOrderedFile")
                <<"total number of sectors: "<<nSector
                <<" ["<<(*s1pattern.begin()).first<<","
                <<(*s1pattern.rbegin()).first<<"]\n";
-            if(bankReader.GetContentType()==
+            if(bankReader->GetContentType()==
                FTKPatternBySectorReader::CONTENT_NOTMERGED) {
                logging.Warning("sectorOrderedFile")
                   <<"This bank is not merged, coverage details unknown\n";
@@ -114,17 +125,18 @@ int main(int argc, char const *argv[]) {
                TH1D *h_s100_covPattern=
                   new TH1D("h_s100_covPattern",";sector;coverage*npattern",
                            nBin100,0,nBin100*100.);
-               std::map<int,std::map<int,int> > scMap;
-               bankReader.GetNPatternsBySectorCoverage(scMap);
+               FTKPatternBySectorReader::SectorByCoverage_t 
+                  const &scMap=bankReader->GetSectorByCoverage();
                uint64_t covPatt=0;
                uint64_t npattTotal=0;
-               for(std::map<int,std::map<int,int> >::const_iterator
-                      is=scMap.begin();is!=scMap.end();is++) {
-                  int sector=(*is).first;
-                  for(std::map<int,int>::const_iterator ic=(*is).second.begin();
-                      ic!=(*is).second.end();ic++) {
-                     int coverage=(*ic).first;
-                     int npattern=(*ic).second;
+               for(FTKPatternBySectorReader::SectorByCoverage_t::const_iterator
+                      iCov=scMap.begin();iCov!=scMap.end();iCov++) {
+                  int coverage=(*iCov).first;
+                  for(FTKPatternBySectorReader::SectorMultiplicity_t
+                         ::const_iterator iSector=(*iCov).second.begin();
+                      iSector!=(*iCov).second.end();iSector++) {
+                     int sector=(*iSector).first;
+                     int npattern=(*iSector).second;
                      h_coverage100->Fill(coverage,npattern);
                      h_coverage1000->Fill(coverage,npattern);
                      h_s100_covPattern->Fill(sector,coverage*npattern);
@@ -187,9 +199,156 @@ int main(int argc, char const *argv[]) {
                   sectorPatterns[sectorID]++;
                   npatt++;
                }
-               logging.Info("stat")<<"non-empty sectors: "<<sectorPatterns.size()<<"\n";
+               logging.Info("stat")<<"non-empty sectors: bank "
+                                   <<sectorPatterns.size()
+                                   <<" total "<<s1pattern.size()<<"\n";
+            }
+            // analyze lookup-tables
+            for(int layer=0;layer<16;layer++) {
+               TString treeName(TString::Format("Layer%d",layer));
+               tree=0;
+               bankFile->GetObject(treeName,tree);
+               if(!tree) break;
+               Int_t nData;
+               tree->SetBranchAddress("nData",&nData);
+               nDataMax.resize(layer+1);
+               for(int i=0;i<tree->GetEntries();i++) {
+                  tree->GetEntry(i);
+                  if(nData>nDataMax[layer]) nDataMax[layer]=nData;
+               }
+               Int_t nPattern,firstPattern;
+               vector<Int_t> data(nDataMax[layer]);
+               tree->SetBranchAddress("data",data.data());
+               tree->SetBranchAddress("nPattern",&nPattern);
+               tree->SetBranchAddress("firstPattern",&firstPattern);
+               TH1D *hist_nPattern=0,*hist_nData=0,*hist_iPatt=0;
+               TH1D *hist_pattDensity=0, *hist_pattDensity20=0,
+                  *hist_iPatt8=0,*hist_patt8Data=0,
+                  *hist_pattData=0,*hist_nbits=0;
+               int nPatternTotal=0;
+               int nDataTotal=0;
+               int iPattTotal=0;
+               int iPatt8Total=0;
+               if(statFile) {
+                  statFile->cd();
+                  hist_nPattern=new TH1D
+                     (TString::Format("hist_nPattern%d",layer),";nPattern",
+                      1000,0.5,10000.5);
+                  hist_nData=new TH1D
+                     (TString::Format("hist_nData%d",layer),";nData",
+                      1000,0.5,10000.5);
+                  hist_iPatt=new TH1D
+                     (TString::Format("hist_iPatt%d",layer),";iPatt",
+                      1000,0.5,100000.5);
+                  hist_iPatt8=new TH1D
+                     (TString::Format("hist_iPatt8%d",layer),";iPatt8",
+                      1000,0.5,100000.5);
+                  hist_pattDensity=new TH1D
+                     (TString::Format("hist_pattDensity%d",layer),
+                      ";nPattern/range",100,0.,1.);
+                  hist_pattDensity20=new TH1D
+                     (TString::Format("hist_pattDensity20_%d",layer),
+                      ";nPattern/range (nPattern>=20)",100,0.,1.);
+                  hist_pattData=new TH1D
+                     (TString::Format("hist_pattData%d",layer),
+                     ";data", 256,-0.5,255.5);
+                  hist_patt8Data=new TH1D
+                     (TString::Format("hist_patt8Data%d",layer),
+                      ";data8", 256,-0.5,255.5);
+                  hist_nbits=new TH1D
+                     (TString::Format("hist_nbits%d",layer),
+                      ";data8", 9,-0.5,8.5);
+               }
+               vector<uint8_t> patterns;
+               patterns.reserve(1000000);
+               for(int i=0;i<tree->GetEntries();i++) {
+                  tree->GetEntry(i);
+                  nPatternTotal += nPattern;
+                  nDataTotal += nData;
+                  // expand data
+                  int ipatt=firstPattern & 0x7;
+                  int ipatt0=ipatt;
+                  patterns.resize(0);
+                  patterns.push_back(1<<ipatt);
+                  for(int iData=0;iData<nData;) {
+                     int d=data[iData++];
+                     if(d>=0xf0) {
+                        for(int k=0;k<d-0xee;k++) {
+                           ipatt ++;
+                           size_t pos8=ipatt>>3;
+                           if(patterns.size()<=pos8) {
+                              patterns.resize(pos8+1);
+                           }
+                           patterns[pos8] |= 1<<(ipatt &7);
+                        }
+                     } else {
+                        // process one pattern
+                        uint32_t delta=1;
+                        while(d & 0x80) {
+                           // pattern with more than 7 bits
+                           //  add non-zero high bits in groups of 4 bits
+                           int shift=((d>>2)&0x3c)-25;
+                           delta += ((uint32_t)(d&0xf))<<shift;
+                           d=data[iData++];
+                        }
+                        delta += d;
+                        ipatt += delta;
+                        size_t pos8=ipatt>>3;
+                        if(patterns.size()<=pos8) {
+                           patterns.resize(pos8+1);
+                        }
+                        patterns[pos8] |= 1<<(ipatt &7);
+                     }
+                  }
+                  // 
+                  int iPatt8=patterns.size();
+                  if(statFile) {
+                     for(int iData=0;iData<nData;iData++) {
+                        hist_pattData->Fill(data[iData]);
+                     }
+                     for(int k=0;k<iPatt8;k++) {
+                        hist_patt8Data->Fill(patterns[k]);
+                        int mult=patterns[k];
+                        mult=(mult & 0x55)+((mult>>1)&0x55);
+                        mult=(mult & 0x33)+((mult>>2)&0x33);
+                        mult=(mult & 0xf)+(mult>>4);
+                        hist_nbits->Fill(mult);
+                     }
+
+                     hist_nPattern->Fill(nPattern);
+                     hist_nData->Fill(nData);
+                     hist_iPatt->Fill(ipatt);
+                     hist_iPatt8->Fill(iPatt8);
+                     int range=ipatt-ipatt0+1;
+                     hist_pattDensity->Fill((nPattern)/(double)range);
+                     if(nPattern>=20) {
+                        hist_pattDensity20->Fill((nPattern)/(double)range);
+                     }
+                  }
+                  iPattTotal += ipatt-(firstPattern & 0x7);
+                  iPatt8Total += iPatt8;
+               }
+               logging.Info("compress")
+                  <<"layer="<<layer<<" ndataMax="<<nDataMax[layer]
+                  <<" nPatternTotal="<<nPatternTotal
+                  <<" nDataTotal="<<nDataTotal
+                  <<" niPattTotal="<<iPattTotal
+                  //<<" fractionNIpatt="<<((double)nPatternTotal)/iPattTotal
+                  <<" fractionNpatt="<<((double)nDataTotal)/nPatternTotal
+                  <<" fraction8Npatt="<<((double)iPatt8Total)/nPatternTotal
+                  <<"\n";
+               if(statFile) {
+                  hist_nPattern->Write();
+                  hist_nData->Write();
+                  hist_nbits->Write();
+                  hist_iPatt->Write();
+                  hist_iPatt8->Write();
+                  hist_pattData->Write();
+                  hist_patt8Data->Write();
+                  hist_pattDensity->Write();
+                  hist_pattDensity20->Write();
+               }
             }
-            delete bankFile;
          }
          ifilesRead++;
       }
@@ -221,7 +380,7 @@ int main(int argc, char const *argv[]) {
          h_s100_patternPerSector->Write();
       } else {
          logging.Warning("statistics")
-            <<"no pattern data was found (bank is empty)\n";
+            <<"no output file specified\n";
       }
    }
    if(statFile) delete statFile;
-- 
GitLab