diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/CMakeLists.txt b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..42e4d9119be17cd2fc08db80f8698aa7879df7a2
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/CMakeLists.txt
@@ -0,0 +1,26 @@
+################################################################################
+# Package: L1CaloFEXSim
+################################################################################
+
+# Declare the package name:
+atlas_subdir( L1CaloFEXSim )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs( PUBLIC
+                          Control/AthenaBaseComps 
+			  Trigger/TrigT1/L1CaloFEXToolInterfaces
+                          Event/xAOD/xAODTruth
+                          Event/xAOD/xAODJet  )
+
+atlas_add_library( L1CaloFEXSimLib
+                   L1CaloFEXSim/*.h src/*.cxx
+                   PUBLIC_HEADERS L1CaloFEXSim
+                   LINK_LIBRARIES AthenaBaseComps CaloEvent xAODTrigL1Calo CaloIdentifier xAODTruth xAODJet)
+
+atlas_add_component( L1CaloFEXSim
+                     src/components/*.cxx
+                     LINK_LIBRARIES AthenaBaseComps L1CaloFEXSimLib L1CaloFEXToolInterfaces xAODTruth xAODJet)
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+atlas_install_joboptions( share/*.py )
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXCompression.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXCompression.h
new file mode 100644
index 0000000000000000000000000000000000000000..b35ce599da5f18eb1c4bc68957d04c05e60c71a7
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXCompression.h
@@ -0,0 +1,78 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+/***************************************************************************
+                          eFEXCompression.h  -  description
+                             -------------------
+    begin                : 07-02-2019 
+    email                : Alan.Watson@cern.ch antonio.jacques.costa@cern.ch
+ ***************************************************************************/
+
+                                                                                
+ #ifndef eFEXCompression_H
+ #define eFEXCompression_H
+                                                                                
+#include <array>
+
+namespace LVL1 {
+
+/**
+LAr supercell data are received by the eFEX in a 10-bit multi-linear encoded form.
+This simple utility class contains 3 functions:
+  - Compress:  encodes a signed integer MeV value
+  - Expand:    decodes a 10 bit unsigned int into a signed integer MeV value
+  - Threshold: applies a threshold (in MeV) to the compressed code, zeroing if below
+  - Linearize: decodes a 10 bit unsigned int into the unsigned 16 bit eFEX ET with
+               least count of 25 MeV. A user-defined threshold (in MeV) can be 
+               applied, but as the eFEX ET is positive a negative threshold is
+               equivalent to a threshold of 0.
+  */
+class eFEXCompression {
+
+public: 
+  /** Compress data */
+  static unsigned int Compress(int Et);
+  /** Uncompress data */
+  static int Expand(unsigned int code);
+  /** Apply threshold to compressed data */
+  static unsigned int Threshold(unsigned int code, int threshold = -800);
+  /** Linearize LAr code to eFEX internal format */
+  static unsigned int Linearize(unsigned int code, int threshold = 0);
+ 
+private: 
+  /** Maximum ET value that can be encoded */
+  static const int s_maxET = 1019200;
+  /** Number of ranges */
+  static const unsigned int s_nRanges = 6;
+  /** Step sizes in each range, MeV */
+  static const int s_steps[s_nRanges];
+  /** Minimum ET values in each range, MeV */
+  static const int s_minET[s_nRanges];
+  /** Minimum code value in each range */
+  static const int s_minCode[s_nRanges];
+  /** Indicates no data present */
+  static const int s_NoData = 0;
+  /** LAr underflow code */
+  static const unsigned int s_LArUnderflow = 1;
+  /** LAr overflow code */
+  static const unsigned int s_LArOverflow  = 1020;
+  /** Reserved code value */
+  static const unsigned int s_LArReserved  = 1021;
+  /** Invalid code value */
+  static const unsigned int s_LArInvalid   = 1022;
+  /** LAr saturated code */
+  static const unsigned int s_LArSaturated = 1023;
+  /** Maximum code value */
+  static const unsigned int s_LArMaxCode   = 1023;
+  /** L1Calo ET digit step */
+  static const unsigned int s_eFEXstep     = 25;
+  /** L1Calo saturated/overflow */
+  static const unsigned int s_eFEXOverflow = 0xffff;
+  /** Error return value */
+  static const int s_error = -999;
+};
+
+
+}//end of ns
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXDriver.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXDriver.h
new file mode 100644
index 0000000000000000000000000000000000000000..74f06ac8da74b1fa340343c7c9d64ad0da507af3
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXDriver.h
@@ -0,0 +1,58 @@
+#ifndef EFEXDRIVER_H
+#define EFEXDRIVER_H
+
+// STL
+#include <string>
+
+// Athena/Gaudi
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "L1CaloFEXSim/eTowerBuilder.h"
+#include "L1CaloFEXSim/eSuperCellTowerMapper.h"
+#include "L1CaloFEXToolInterfaces/IeFEXSysSim.h"
+#include "L1CaloFEXSim/eFEXSim.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "xAODTrigL1Calo/TriggerTowerContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+
+class CaloIdManager;
+
+namespace LVL1 {
+
+class eFEXDriver : public AthAlgorithm
+{
+ public:
+  //using AthReentrantAlgorithm::AthReentrantAlgorithm;
+
+  eFEXDriver(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~eFEXDriver();
+
+  virtual StatusCode initialize();
+  virtual StatusCode execute(/*const EventContext& ctx*/);// const;
+  StatusCode finalize();
+
+ private:
+
+  int m_numberOfEvents = 0;
+
+  SG::WriteHandleKey<LVL1::eTowerContainer> m_eTowerContainerSGKey {this, "MyETowers", "eTowerContainer", "MyETowers"};
+
+  //SG::WriteHandleKey<eFEXOutputCollection> m_eFEXOutputCollectionSGKey {this, "MyOutputs", "eFEXOutputCollection", "MyOutputs"};
+
+  SG::ReadHandleKey<CaloCellContainer> m_scellsCollectionSGKey {this, "SCell", "SCell", "SCell"};
+
+  ToolHandle<IeTowerBuilder> m_eTowerBuilderTool {this, "eTowerBuilderTool", "LVL1::eTowerBuilder", "Tool that builds eTowers for simulation"};
+  ToolHandle<IeSuperCellTowerMapper> m_eSuperCellTowerMapperTool {this, "eSuperCellTowerMapperTool", "LVL1::eSuperCellTowerMapper", "Tool that maps supercells to eTowers"};
+  ToolHandle<IeFEXSysSim> m_eFEXSysSimTool {this, "eFEXSysSimTool", "LVL1::eFEXSysSim", "Tool that creates the eFEX System Simulation"};
+
+  std::map<Identifier, std::pair<int,int> > m_cell_to_tower_map;
+
+};
+
+} // end of LVL1 namespace
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXFPGA.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXFPGA.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc3351ad5774eab2a5499b4ec32ff44a69f0c019
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXFPGA.h
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXFPGA.h  -  
+//                              -------------------
+//     begin                : 15 10 2019
+//     email                : jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+
+#ifndef eFEXFPGA_H
+#define eFEXFPGA_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "AthenaKernel/CLASS_DEF.h"
+#include "L1CaloFEXToolInterfaces/IeFEXFPGA.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "L1CaloFEXToolInterfaces/IeFEXtauAlgo.h"
+#include "L1CaloFEXToolInterfaces/IeFEXegAlgo.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+
+namespace LVL1 {
+  
+  //Doxygen class description below:
+  /** The eFEXFPGA class defines the structure of a single eFEX FPGA
+      Its purpose is:
+      - to emulate the steps taken in processing data for a single eFEX FPGA in hardware and firmware
+      - It will need to interact with eTowers and produce the eTOBs.  It will be created and handed data by eFEXSim
+  */
+  
+  class eFEXFPGA : public AthAlgTool, virtual public IeFEXFPGA {
+    
+  public:
+    /** Constructors */
+    eFEXFPGA(const std::string& type,const std::string& name,const IInterface* parent);
+
+    /** standard Athena-Algorithm method */
+    virtual StatusCode initialize() ;
+    /** Destructor */
+    virtual ~eFEXFPGA();
+
+    virtual StatusCode init(int id, int efexid) override ;
+
+    virtual StatusCode execute() override ;
+
+    virtual void reset() override ;
+
+    virtual int ID() override {return m_id;}
+
+    virtual void SetTowersAndCells_SG( int [][6] ) override ;
+
+    /** Internal data */
+  private:
+
+    int m_id;
+    int m_efexid;
+
+    int m_eTowersIDs [10][6];
+    std::map<int,eTower> m_eTowersColl;
+
+    CaloCellContainer m_sCellsCollection;
+
+    SG::ReadHandleKey<LVL1::eTowerContainer> m_eFEXFPGA_eTowerContainerKey {this, "MyETowers", "eTowerContainer", "Input container for eTowers"};
+
+    //SG::ReadHandleKey<eFEXOutputCollection> m_eFEXFPGA_eFEXOutputCollectionKey {this, "MyOutputs", "eFEXOutputCollection", "Input container for eFEXOutputCollection"};
+
+    ToolHandle<IeFEXtauAlgo> m_eFEXtauAlgoTool {this, "eFEXtauAlgoTool", "LVL1::eFEXtauAlgo", "Tool that runs the eFEX tau algorithm"};
+    ToolHandle<IeFEXegAlgo> m_eFEXegAlgoTool {this, "eFEXegAlgoTool", "LVL1::eFEXegAlgo", "Tool that runs the eFEX e/gamma algorithm"};
+    
+  };
+  
+} // end of namespace
+
+//CLASS_DEF( LVL1::eFEXFPGA , 32201201 , 1 )
+
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXNtupleWriter.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXNtupleWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..14772c76742f091694060d43136cc63613fb9ac6
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXNtupleWriter.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXNtupleWriter.h  -  
+//                              -------------------
+//     begin                : 28 02 2020
+//     email                : tong.qiu@cern.ch
+//  **************************************************************************
+#ifndef EFEXTUPLEWRITER_H
+#define EFEXTUPLEWRITER_H
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "TTree.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "xAODTruth/TruthParticle.h"
+#include <memory>
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+
+namespace LVL1 {
+class eFEXNtupleWriter : public AthAlgorithm
+{
+public:
+  // this is a standard algorithm constructor
+  eFEXNtupleWriter(const std::string& name, ISvcLocator* pSvcLocator);
+  ~eFEXNtupleWriter();
+  // these are the functions inherited from Algorithm
+  StatusCode initialize ();
+  StatusCode execute ();
+  StatusCode finalize ();
+
+private:
+  eFEXOutputCollection* m_eFEXOutputCollection;
+  //std::shared_ptr<eFEXOutputCollection> m_eFEXOutputCollection;
+  float m_eg_nTOBs;
+  bool m_load_truth_jet;
+  std::vector<float> m_em;
+  std::vector<float> m_had;
+  std::vector<float> m_truth_e_eta;
+  std::vector<float> m_truth_e_phi;
+  std::vector<float> m_truth_e_ET;
+  std::vector<float> m_truth_jet_eta;
+  std::vector<float> m_truth_jet_phi;
+  std::vector<float> m_truth_jet_ET;
+  std::vector<float> m_truth_tauvisible_eta;
+  std::vector<float> m_truth_tauvisible_phi;
+  std::vector<float> m_truth_tauvisible_ET;
+  std::vector<float> m_eg_haveseed;
+  std::vector<float> m_eg_eta;
+  std::vector<float> m_eg_phi;
+  std::vector<float> m_eg_ET;
+  std::vector<float> m_eg_WstotNum;
+  std::vector<float> m_eg_WstotDen;
+  std::vector<float> m_eg_RetaNum;
+  std::vector<float> m_eg_RetaDen;
+  std::vector<float> m_eg_RhadNum;
+  std::vector<float> m_eg_RhadDen;
+  std::vector<float> m_tau_Iso;
+  std::vector<float> m_tau_Et;
+  std::vector<float> m_tau_isCentralTowerSeed;
+  std::string m_jet_container_name = "AntiKt10TruthJets";
+  TTree *m_myTree;
+  
+  StatusCode loadegAlgoVariables();
+  StatusCode loadtauAlgoVariables();
+  StatusCode loadTruthElectron();
+  StatusCode loadTruthJets();
+  StatusCode loadTruthTau();
+  std::unique_ptr<TLorentzVector> visibleTauP4(const xAOD::TruthParticle*);
+  std::unique_ptr<TLorentzVector> invisibleTauP4(const xAOD::TruthParticle*);
+  const xAOD::TruthParticle* getMother(const xAOD::TruthParticle*, int);
+};
+}
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXOutputCollection.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXOutputCollection.h
new file mode 100644
index 0000000000000000000000000000000000000000..f51457937c31e1e6b5e7763b6ca142025ec15697
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXOutputCollection.h
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXOutputCollection.h  -  
+//                              -------------------
+//     begin                : 28 02 2020
+//     email                : tong.qiu@cern.ch
+//  **************************************************************************
+
+#pragma once
+#include "AthenaKernel/CLASS_DEF.h"
+#include <map>
+#include <iostream>
+#include <vector>
+#include <string>
+
+namespace LVL1 {
+  class eFEXOutputCollection
+  {
+  public:
+    eFEXOutputCollection() {};
+    ~eFEXOutputCollection();
+    void clear();
+    void addValue_eg(std::string, float);
+    void fill_eg();
+    void addValue_tau(std::string, float);
+    void fill_tau();
+    int size();
+    std::map<std::string, float>* get_eg(int);
+    std::map<std::string, float>* get_tau(int);
+  private:
+    std::map<std::string, float> m_values_tem_eg;
+    std::vector<std::map<std::string, float>*> m_allvalues_eg;
+    std::map<std::string, float> m_values_tem_tau;
+    std::vector<std::map<std::string, float>*> m_allvalues_tau;
+  };
+}
+CLASS_DEF( LVL1::eFEXOutputCollection, 32202262 , 1 )
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXSim.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXSim.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd845e6e6335569da1ca6825bdddf31f92697506
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXSim.h
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXSim.h  -  
+//                              -------------------
+//     begin                : 22 08 2019
+//     email                : jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+
+#ifndef eFEXSim_H
+#define eFEXSim_H
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "L1CaloFEXToolInterfaces/IeFEXSim.h"
+#include "AthenaKernel/CLASS_DEF.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eFEXFPGA.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+namespace LVL1 {
+  
+  //Doxygen class description below:
+  /** The eFEXSim class defines the structure of a single eFEX
+      Its purpose is:
+      - to emulate the steps taken in processing data for a single eFEX in hardware and firmware
+      - It will need to interact with eTowers and produce the eTOBs.  It will be created and handed data by eFEXSysSim
+  */
+  
+  class eFEXSim : public AthAlgTool, virtual public IeFEXSim {
+    
+  public:
+
+    /** Constructors */
+    eFEXSim(const std::string& type,const std::string& name,const IInterface* parent);
+
+    /** Destructor */
+    virtual ~eFEXSim();
+
+    /** standard Athena-Algorithm method */
+    virtual StatusCode initialize() ;
+    /** standard Athena-Algorithm method */
+    virtual StatusCode finalize  () ;
+
+    virtual void init (int id) override ;
+
+    virtual void reset () override ;
+
+    virtual void execute() override ;
+
+    virtual int ID() override {return m_id;}
+    
+    virtual void SetTowersAndCells_SG(int tmp[10][18]) override;
+
+    virtual StatusCode NewExecute(int tmp[10][18]) override;
+
+    /** Internal data */
+  private:
+
+    int m_id;
+
+    int m_eTowersIDs [10][18];
+    std::map<int,eTower> m_eTowersColl;
+    CaloCellContainer m_sCellsCollection;
+    std::vector<eFEXFPGA*> m_eFEXFPGACollection;
+
+    ToolHandle<IeFEXFPGA> m_eFEXFPGATool {this, "eFEXFPGATool", "LVL1::eFEXFPGA", "Tool that simulates the FPGA hardware"};
+
+    
+  };
+  
+} // end of namespace
+
+//CLASS_DEF( LVL1::eFEXSim , 32201200 , 1 )
+
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXSysSim.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXSysSim.h
new file mode 100644
index 0000000000000000000000000000000000000000..791cd2f60a592795b7000a955e729ab17891782c
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXSysSim.h
@@ -0,0 +1,77 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXSysSim.h  -  
+//                              -------------------
+//     begin                : 12 07 2019
+//     email                : alison.elliot@cern.ch, jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+
+#ifndef eFEXSysSim_H
+#define eFEXSysSim_H
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "L1CaloFEXToolInterfaces/IeFEXSysSim.h"
+#include "AthenaKernel/CLASS_DEF.h"
+#include "L1CaloFEXSim/eFEXSim.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+namespace LVL1 {
+  
+  //Doxygen class description below:
+  /** The eFEXSysSim class defines the structure of the eFEX system
+      Its purpose is:
+      - to follow the structure of the 24 eFEXes and their FPGAs in as much
+      detail as necessary to simulate the output of the system
+      It will need to interact with eTowers and produce the eTOBs
+  */
+
+  class eFEXSysSim : public AthAlgTool, virtual public IeFEXSysSim {
+    
+  public:
+    
+    /** Constructors */
+
+    eFEXSysSim(const std::string& type,const std::string& name,const IInterface* parent);
+    /** Destructor */
+    eFEXSysSim&& operator= (const eFEXSysSim& ) = delete;
+
+    /** standard Athena-Algorithm method */
+    virtual StatusCode initialize() ;
+    /** standard Athena-Algorithm method */
+    virtual StatusCode finalize  () ;
+
+    virtual StatusCode execute() override ;
+
+    virtual void init() override ;
+
+    virtual void cleanup() override;
+
+    virtual int calcTowerID(int eta, int phi, int mod) override ;
+
+    /** Internal data */
+  private:
+
+    std::vector<eFEXSim*>  m_eFEXCollection;
+    
+    ToolHandle<IeFEXSim> m_eFEXSimTool       {this, "eFEXSimTool",    "LVL1::eFEXSim",    "Tool that creates the eFEX Simulation"};
+
+    SG::ReadHandleKey<LVL1::eTowerContainer> m_eTowerContainerSGKey {this, "MyETowers", "eTowerContainer", "Input container for eTowers"};
+    SG::ReadHandleKey<CaloCellContainer> m_scellsCollectionSGKey {this, "SCell", "SCell", "SCell"};
+
+    std::map<int,eTower> m_eTowersColl;
+    
+  };
+  
+} // end of namespace
+
+//CLASS_DEF( LVL1::eFEXSysSim , 32201258 , 1 )
+
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXegAlgo.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXegAlgo.h
new file mode 100644
index 0000000000000000000000000000000000000000..78c2ec5db51bbbb7eb8098b44e1db7d2dfa63b43
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXegAlgo.h
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXegAlgo.h  -  
+//                              -------------------
+//     begin                : 24 02 2020
+//     email                : antonio.jacques.costa@cern.ch ulla.blumenschein@cern.ch tong.qiu@cern.ch
+//  ***************************************************************************/
+
+
+#ifndef eFEXegAlgo_H
+#define eFEXegAlgo_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "L1CaloFEXToolInterfaces/IeFEXegAlgo.h"
+#include "AthenaKernel/CLASS_DEF.h"
+#include "L1CaloFEXSim/eFEXegTOB.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "StoreGate/StoreGateSvc.h"
+
+namespace LVL1 {
+  
+  //Doxygen class description below:
+  /** The eFEXegAlgo class calculates the egamma TOB variables: Reta, Rhad and Wstot
+  */
+  
+  class eFEXegAlgo : public AthAlgTool, virtual public IeFEXegAlgo {
+
+  public:
+    /** Constructors */
+    eFEXegAlgo(const std::string& type, const std::string& name, const IInterface* parent);
+
+    /** standard Athena-Algorithm method */
+    virtual StatusCode initialize() ;
+    
+    /** Destructor */
+    virtual ~eFEXegAlgo();
+
+    virtual StatusCode safetyTest() override;
+    virtual void setup(int inputTable[3][3]) override; 
+
+    virtual std::vector<unsigned int> getReta() override;
+    virtual void getRhad(std::vector<unsigned int> & ) override;
+    virtual void getWstot(std::vector<unsigned int> & ) override;
+    virtual void getRealPhi(float & phi) override;
+    virtual void getRealEta(float & eta) override;
+    virtual std::unique_ptr<eFEXegTOB> geteFEXegTOB() override;
+    virtual unsigned int getET() override;
+    virtual void getWindowET(int layer, int jPhi, int SCID, unsigned int &) override;
+    virtual bool haveSeed() override {return m_haveseed;};
+  
+    virtual void getCoreEMTowerET(unsigned int & et) override;
+    virtual void getCoreHADTowerET(unsigned int & et) override;
+  private:
+    virtual void setSeed() override;
+    bool m_seed_UnD = false; 
+    unsigned int m_seedID = 999;
+    int m_eFEXegAlgoTowerID[3][3];
+    float m_reta;
+    float m_rhad;
+    float m_wstot;
+    bool m_haveseed;
+
+    SG::ReadHandleKey<LVL1::eTowerContainer> m_eFEXegAlgo_eTowerContainerKey {this, "MyETowers", "eTowerContainer", "Input container for eTowers"};
+
+  };
+  
+} // end of namespace
+
+//CLASS_DEF( LVL1::eFEXegAlgo, 32202260 , 1 )
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXegTOB.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXegTOB.h
new file mode 100644
index 0000000000000000000000000000000000000000..f48b37bce3dba612193a01b01e116fb7f4511e19
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXegTOB.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXegTOB.h  -  
+//                              -------------------
+//     begin                : 17 01 2020
+//     email                : tong.qiu@cern.ch
+//  **************************************************************************
+
+
+#pragma once
+#include "AthenaKernel/CLASS_DEF.h"
+
+namespace LVL1 {
+  class eFEXegTOB
+  {
+    //eFEXegAlgo class description below:
+    /** The eFEXegAlgo.h class store the energy, the location and the isolation variables of eFEX TOBs
+     */
+  private:
+    unsigned int m_eta;
+    unsigned int m_phi;
+    unsigned int m_ET;
+    unsigned int m_Reta_Num;
+    unsigned int m_Reta_Den;
+    unsigned int m_Rhad_Num;
+    unsigned int m_Rhad_Den;
+    unsigned int m_Wstot_Num;
+    unsigned int m_Wstot_Den;
+    unsigned int m_FPGA_ID;
+    unsigned int m_eFEX_ID;
+    bool m_seed_UnD;
+    unsigned int m_seed;
+    
+  public:
+    eFEXegTOB();
+    ~eFEXegTOB() {};
+    
+    inline unsigned  int getEta() const {return m_eta;}
+    inline unsigned  int getPhi() const {return m_phi;}
+    inline unsigned  int getET() const {return m_ET;}
+    inline unsigned  int getFPGAID() const {return m_FPGA_ID;}
+    inline unsigned  int geteFEXID() const {return m_eFEX_ID;}
+    // if seed is above (higher phi) central supercell of the seed
+    inline bool getSeedUnD() const {return m_seed_UnD;}
+    // seed index in eta
+    inline unsigned  int getSeed() const {return m_seed;}
+    inline unsigned  int getRetaNum() const {return m_Reta_Num;}
+    inline unsigned  int getRetaDen() const {return m_Reta_Den;}
+    inline unsigned  int getRhadNum() const {return m_Rhad_Num;}
+    inline unsigned  int getRhadDen() const {return m_Rhad_Den;}
+    inline unsigned  int getWstotNum() const {return m_Wstot_Num;}
+    inline unsigned  int getWstotDen() const {return m_Wstot_Den;}
+    
+    unsigned int setEta(unsigned int);
+    unsigned int setPhi(unsigned int);
+    unsigned int setET(unsigned int);
+    unsigned int setFPGAID(unsigned int);
+    unsigned int seteFEXID(unsigned int);
+    bool setSeedUnD(bool);
+    unsigned int setSeed(unsigned int);
+    unsigned int setRetaNum(unsigned int);
+    unsigned int setRetaDen(unsigned int);
+    unsigned int setRhadNum(unsigned int);
+    unsigned int setRhadDen(unsigned int);
+    unsigned int setWstotNum(unsigned int);
+    unsigned int setWstotDen(unsigned int);
+  };
+  
+} // end of namespace
+
+CLASS_DEF( LVL1::eFEXegTOB, 32202261 , 1 )
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgo.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgo.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c08922864ac98092a68f1064a56ccf3505cc388
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgo.h
@@ -0,0 +1,86 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXtauAlgo.h  -  
+//                              -------------------
+//     begin                : 06 05 2020
+//     email                : nicholas.andrew.luongo@cern.ch
+//  ***************************************************************************/
+
+
+#ifndef eFEXtauAlgo_H
+#define eFEXtauAlgo_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "L1CaloFEXToolInterfaces/IeFEXtauAlgo.h"
+#include "AthenaKernel/CLASS_DEF.h"
+#include "L1CaloFEXSim/eFEXtauTOB.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+namespace LVL1 {
+  
+  //Doxygen class description below:
+  /** The eFEXtauAlgo class calculates the tau TOB variables
+  */
+  
+  class eFEXtauAlgo : public AthAlgTool, virtual public IeFEXtauAlgo {
+    
+  public:
+    /** Constructors */
+    eFEXtauAlgo(const std::string& type, const std::string& name, const IInterface* parent);
+
+    /** standard Athena-Algorithm method */
+    virtual StatusCode initialize() ;
+    
+    /** Destructor */
+    virtual ~eFEXtauAlgo();
+
+    virtual StatusCode safetyTest() override;
+    virtual void setup(int inputTable[3][3]) override;
+
+    /** standard Athena-Algorithm method */
+    //virtual StatusCode initialize();
+
+    /** standard Athena-Algorithm method */
+    //virtual StatusCode finalize();
+
+    virtual bool isCentralTowerSeed() override;
+    virtual eFEXtauTOB* getTauTOB() override;
+    virtual float getIso() override;
+    virtual unsigned int getEt() override;
+    virtual unsigned int getBitwiseEt() override;
+
+  protected:
+
+  private:
+    int m_eFexalgoTowerID[3][3];
+
+    void buildLayers();
+    void setSupercellSeed();
+    void setUnDAndOffPhi();
+    bool getUnD();
+	
+    unsigned int m_em0cells[3][3];
+    unsigned int m_em1cells[12][3];
+    unsigned int m_em2cells[12][3];
+    unsigned int m_em3cells[3][3];
+    unsigned int m_hadcells[3][3];
+    unsigned int m_twrcells[3][3];
+    unsigned int m_seed;
+    unsigned int m_et;
+    float m_iso;
+    bool m_cellsSet = false;
+    bool m_und = true;
+    bool m_offPhi = 2;
+
+    SG::ReadHandleKey<LVL1::eTowerContainer> m_eFEXtauAlgo_eTowerContainerKey {this, "MyETowers", "eTowerContainer", "Input container for eTowers"};
+
+  };
+  
+} // end of namespace
+
+//CLASS_DEF( LVL1::eFEXtauAlgo , 140708609 , 1 )
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauTOB.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauTOB.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f401207dbc265c5ecb2d50597d17f36f1554cec
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauTOB.h
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXtauTOB.h  -  
+//                              -------------------
+//     begin                : 01 03 2020
+//     email                : nicholas.andrew.luongo@cern.ch
+//  **************************************************************************
+
+
+#pragma once
+#include "AthenaKernel/CLASS_DEF.h"
+
+namespace LVL1 {
+  class eFEXtauTOB
+  {
+    //eFEXtauAlgo class description below:
+    /** The eFEXtauAlgo.h class store the energy, the location and the isolation variables of eFEX TOBs
+     */
+  private:
+    unsigned int m_eta;
+    unsigned int m_phi;
+    unsigned int m_et;
+    unsigned int m_bitwise_et;
+    float m_iso;
+    unsigned int m_reta_num;
+    unsigned int m_reta_den;
+    unsigned int m_rhad_num;
+    unsigned int m_rhad_den;
+    unsigned int m_wstot_num;
+    unsigned int m_wstot_den;
+    unsigned int m_fpga_id;
+    unsigned int m_efex_id;
+    bool m_seed_und;
+    unsigned int m_seed;
+    
+  public:
+    eFEXtauTOB();
+    ~eFEXtauTOB() {};
+    
+    inline unsigned int getEta() const {return m_eta;}
+    inline unsigned int getPhi() const {return m_phi;}
+    inline unsigned int getEt() const {return m_et;}
+    inline unsigned int getBitwiseEt() const {return m_bitwise_et;}
+    inline float getIso() const {return m_iso;}
+    inline unsigned int getFPGAID() const {return m_fpga_id;}
+    inline unsigned int getEFEXID() const {return m_efex_id;}
+    // if seed is above (higher phi) central supercell of the seed
+    inline bool getSeedUnD() const {return m_seed_und;}
+    // seed index in eta
+    inline unsigned int getSeed() const {return m_seed;}
+    inline unsigned int getRetaNum() const {return m_reta_num;}
+    inline unsigned int getRetaDen() const {return m_reta_den;}
+    inline unsigned int getRhadNum() const {return m_rhad_num;}
+    inline unsigned int getRhadDen() const {return m_rhad_den;}
+    inline unsigned int getWstotNum() const {return m_wstot_num;}
+    inline unsigned int getWstotDen() const {return m_wstot_den;}
+    
+    unsigned int setEta(unsigned int);
+    unsigned int setPhi(unsigned int);
+    unsigned int setEt(unsigned int);
+    unsigned int setBitwiseEt(unsigned int);
+    float setIso(unsigned int);
+    unsigned int setFPGAID(unsigned int);
+    unsigned int setEFEXID(unsigned int);
+    bool setSeedUnD(bool);
+    unsigned int setSeed(unsigned int);
+    unsigned int setRetaNum(unsigned int);
+    unsigned int setRetaDen(unsigned int);
+    unsigned int setRhadNum(unsigned int);
+    unsigned int setRhadDen(unsigned int);
+    unsigned int setWstotNum(unsigned int);
+    unsigned int setWstotDen(unsigned int);
+  };
+  
+} // end of namespace
+
+CLASS_DEF( LVL1::eFEXtauTOB, 32202275 , 1 )
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eSuperCellTowerMapper.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eSuperCellTowerMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..75d1099e9617a7f7f6636ee39f3707cb08af2fb5
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eSuperCellTowerMapper.h
@@ -0,0 +1,55 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef ESUPERCELLTOWERMAPPER_H
+#define ESUPERCELLTOWERMAPPER_H
+
+// STL
+#include <string>
+
+// Athena/Gaudi
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "L1CaloFEXToolInterfaces/IeSuperCellTowerMapper.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "xAODTrigL1Calo/TriggerTowerContainer.h"
+
+class CaloIdManager;
+
+namespace LVL1 {
+
+
+class eSuperCellTowerMapper: public AthAlgTool, virtual public IeSuperCellTowerMapper
+{
+ public:
+  eSuperCellTowerMapper(const std::string& type,const std::string& name,const IInterface* parent);
+  virtual ~eSuperCellTowerMapper();
+
+  /** standard Athena-Algorithm method */
+  virtual StatusCode initialize() ;
+  
+  virtual StatusCode AssignSuperCellsToTowers(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw) override;
+  virtual StatusCode AssignTriggerTowerMapper(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw) override;
+  
+  virtual void reset() override;
+
+ private:
+
+  SG::ReadHandleKey<CaloCellContainer> m_scellsCollectionSGKey {this, "SCell", "SCell", "SCell"};
+  SG::ReadHandleKey<xAOD::TriggerTowerContainer> m_triggerTowerCollectionSGKey {this, "xODTriggerTowers", "xAODTriggerTowers", "xAODTriggerTowers"};
+
+  virtual int FindAndConnectTower(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw,CaloSampling::CaloSample sample,const int region, int layer, const int pos_neg, const int eta_index, const int phi_index, Identifier ID, float et, int prov, bool doPrint) override;
+  virtual int ConnectSuperCellToTower(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw, int iETower, Identifier ID, int iCell, float et, int layer, bool doenergysplit) override;
+  virtual int FindTowerIDForSuperCell(int towereta, int towerphi) override;
+  virtual void PrintCellSpec(const CaloSampling::CaloSample sample, int layer, const int region, const int eta_index, const int phi_index, const int pos_neg, int iETower, int iCell, int prov, Identifier ID, bool doenergysplit) override;
+
+};
+
+} // end of LVL1 namespace
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTower.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTower.h
new file mode 100644
index 0000000000000000000000000000000000000000..4b9e0710b3b691af51f835c3f9f297d6de4c6281
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTower.h
@@ -0,0 +1,149 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eTower.h  -  description
+//                              -------------------
+//     begin                : 19 02 2019
+//     email                : Alan.Watson@cern.ch, jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+
+#ifndef eTower_H
+#define eTower_H
+
+#include <vector>
+#include "AthenaKernel/CLASS_DEF.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+#include "xAODBase/IParticle.h"
+#include "xAODCore/AuxStoreAccessorMacros.h"
+
+namespace LVL1 {
+  
+  //Doxygen class description below:
+  /** The eTower class is an interface object for eFEX trigger algorithms
+      The purposes are twofold:
+      - to provide inputs to the algorithms in a way that reflects the cell
+      structure within a tower (the basic element of an eFEX algorithm window)
+      - to hide the details of the individual data sources, e.g. which hadronic
+      cells are LAr and which are HEC, from the algorithms
+      It needs to contain supercell ET values and a tower coordinate or identifier
+      (not yet defined). ET values should be on the eFEX's internal ET scale, not MeV.
+      This should be a purely transient object, but will need to enter the transient
+      event store (so class_def etc will be needed before it can be used for real)
+  */
+  
+  class eTower {
+    
+  public:
+    
+    /** Constructors */
+    eTower();
+    eTower(float eta, float phi, int id_modifier, int posneg);
+    
+    /** Destructor */
+    virtual ~eTower();
+    
+    /** Clear supercell ET values */
+    void clearET();
+    
+    /** Clear and resize Identifier value vector */
+    void clear_scIDs();
+
+    /** Add to ET of a specified cell in MeV */
+    void addET(float et, int cell);
+
+    /** Add to ET of a specified cell */
+    void recordMD_ET(float et, int cell);
+
+    /** Get coordinates of tower */
+    int iEta();
+    int iPhi();
+    float eta() {return m_eta;};
+    float phi() {return m_phi;};
+    float eta() const {return m_eta;};
+    float phi() const {return m_phi;};
+    
+    void setEta(const float thiseta){ m_eta = thiseta; }
+
+    int id() {return m_tower_id;};
+
+    int id() const {return m_tower_id;}
+
+    float constid() const {return m_tower_id;};
+
+    /** Get ET of a specified cell in MeV */
+    int getET(unsigned int layer, int cell = 0) const;
+    
+    /** Get ET sum of all cells in the eTower in MeV */
+    int getTotalET() const;
+
+    /** Get total ET sum of all cells in a given layer in MeV */
+    int getLayerTotalET(unsigned int layer) const;
+
+    /** Get vector of ET values for a given layer in MeV */
+    std::vector<int> getLayerETvec(unsigned int layer) const;
+    
+    /** Get vector of all ET values in MeV */
+    std::vector<int> getETs() const {return m_et;};
+
+    /** Get ET of a specified cell in MeV FLOAT VERSION */
+    float getET_float(unsigned int layer, int cell = 0) const;
+
+    /** Get ET sum of all cells in the eTower in MeV FLOAT VERSION */
+    float getTotalET_float() const;
+
+    /** Get total ET sum of all cells in a given layer in MeV FLOAT VERSION */
+    float getLayerTotalET_float(unsigned int layer) const;
+
+    /** Get vector of ET values for a given layer in MeV FLOAT VERSION */
+    std::vector<float> getLayerETvec_float(unsigned int layer) const;
+
+    /** Get vector of all ET values in MeV FLOAT VERSION */
+    std::vector<float> getETs_float() const {return m_et_float;};
+
+    void setET(int cell, float et, int layer);
+
+    /** Set supercell position ID **/
+    void setSCID(Identifier ID, int cell, float et, int layer, bool doenergysplit);
+
+    std::vector<Identifier> getSCIDs() const { return m_scID; }
+
+    Identifier getSCID(int cell) const { return m_scID[cell]; }
+
+    std::vector<Identifier> getLayerSCIDs(unsigned int layer) const;
+
+    /** Apply supercell noise cut **/
+    bool noiseCut(int et, int layer);
+
+    void setPosNeg(int posneg);
+
+    inline int getPosNeg() const {return m_posneg;}
+
+    /** Internal data */
+  private:
+    float m_eta;
+    float m_phi;
+    std::vector<Identifier> m_scID;
+    std::vector<int> m_et;    
+    std::vector<float> m_et_float;
+    int m_tower_id;
+    int m_posneg = 0;
+    int m_noisecutPS = 100;
+    int m_noisecutL1 = 100;
+    int m_noisecutL2 = 100;
+    int m_noisecutL3 = 100;
+    int m_noisecutHad = 100;
+
+  };
+  
+} // end of namespace
+
+CLASS_DEF( LVL1::eTower , 32201259 , 1 )
+
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTowerBuilder.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTowerBuilder.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8a0050c288d6122c8b965c854c215475ba6f153
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTowerBuilder.h
@@ -0,0 +1,46 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef ETOWERBUILDER_H
+#define ETOWERBUILDER_H
+
+// STL
+#include <string>
+
+// Athena/Gaudi
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "L1CaloFEXToolInterfaces/IeTowerBuilder.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+class CaloIdManager;
+
+namespace LVL1 {
+
+class eTowerBuilder: public AthAlgTool, virtual public IeTowerBuilder {
+
+ public:
+  eTowerBuilder(const std::string& type,const std::string& name,const IInterface* parent);
+  virtual ~eTowerBuilder();
+
+  virtual void init(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void execute(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void reset() override ;
+
+ private:
+
+  virtual void BuildEMBeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void BuildTRANSeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void BuildEMEeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void BuildHECeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void BuildAllTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) override ;
+  virtual void BuildSingleTower(std::unique_ptr<eTowerContainer> & eTowerContainerRawRaw,float eta, float phi, float keybase, int posneg) override ;
+
+};
+
+} // end of LVL1 namespace
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTowerContainer.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTowerContainer.h
new file mode 100644
index 0000000000000000000000000000000000000000..652bf5b64faf5868b13b1ba12008163a92193f26
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eTowerContainer.h
@@ -0,0 +1,85 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Stolen shamelessly from CaloCellContainer.h and modified as required
+
+#ifndef ETOWERCONTAINER_H
+#define ETOWERCONTAINER_H
+
+/** 
+   @class eTowerContainer
+   @brief Container class for eTower
+
+   eTowerContainer is a container of all eFEX eTowers.
+   It derives from DataVector<eTower>.
+
+ */
+
+#include "AthContainers/DataVector.h"
+#include "AthenaKernel/CLASS_DEF.h"
+#include "L1CaloFEXSim/eTower.h"
+
+#include "Identifier/IdentifierHash.h"
+#include "CxxUtils/PackedArray.h"
+#include "CxxUtils/CachedValue.h"
+#include "AthLinks/tools/findInContainer.h"
+
+namespace LVL1 {
+
+class eTowerContainer : public DataVector<LVL1::eTower>
+{
+
+ public:
+
+
+ /** @brief type to be used for the internal lookup table, and to return list of towers */
+  typedef std::vector<const LVL1::eTower> eTowerVector;
+  
+ /** @brief Return from non-const findTowerVector. */
+  typedef std::vector<LVL1::eTower> MutableeTowerVector;
+  
+  /** @brief Main constructor */
+  eTowerContainer(SG::OwnershipPolicy ownPolicy=SG::OWN_ELEMENTS ) ;
+  //eTowerContainer() ;
+
+  /** @brief Sized constructor */
+  eTowerContainer(size_t n, SG::OwnershipPolicy ownPolicy=SG::OWN_ELEMENTS );
+
+  /**  @brief destructor */  
+  virtual ~eTowerContainer() { };
+
+  /** @brief reimplementation of const push_back */
+  void push_back(float eta, float phi, float keybase, int posneg);
+
+  /** @brief utility function to help speed up accessing towers */
+  bool fillContainerMap();
+
+  /** @brief dump (obsolete) */
+  void print() const;
+
+  /** @brief fast find method given identifier. */ 
+  const LVL1::eTower * findTower(int towerID) const;
+  
+  /** @brief fast find method given identifier. */ 
+  LVL1::eTower * findTower(int towerID);
+
+  /** @brief clear map */
+  void clearContainerMap();
+
+ private:
+  /** @brief get message service */
+  IMessageSvc* msgSvc() const;
+
+  //* @brief Keeps track of the towerID of each eTower associated to each MAP index *.
+  std::map<int,int> m_map_towerID_containerIndex;
+};
+
+}
+CLASS_DEF( LVL1::eTowerContainer , 1143075806 , 1 )
+SG_BASE(LVL1::eTowerContainer, DataVector<LVL1::eTower> );
+
+#endif
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/python/eFEXDriverConfig.py b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/python/eFEXDriverConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..d0a9fd81ee4d19217f9849ab33e68b624fd24d46
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/python/eFEXDriverConfig.py
@@ -0,0 +1,6 @@
+from L1CaloFEXSim.L1CaloFEXSimConf import LVL1__eFEXSim
+
+class Run3eFEXDriver (LVL1__eFEXDriver):
+    __slots__ = []
+    def __init__(self, name):
+        print("GONDOR CALLS FOR AID")
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/eFEXNTuple.py b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/eFEXNTuple.py
new file mode 100644
index 0000000000000000000000000000000000000000..1cb8959c9399c2d6ae264a6f1e077bdcfd0de648
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/eFEXNTuple.py
@@ -0,0 +1,111 @@
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+
+#***************************************************************************
+#                           eFEXNTuple.py  -  
+#                              -------------------
+#     begin                : 28 03 2020
+#     email                : tong.qiu@cern.ch
+#  **************************************************************************
+from __future__ import division
+import ROOT
+import numpy as np
+import math
+
+def delta_phi(phi1, phi2):
+    output = abs(phi1 - phi2)
+    if output > math.pi:
+        output = math.pi * 2. - output
+    return output
+
+def delta_R(eta1, phi1, eta2, phi2):
+    return (delta_phi(phi1, phi2)**2. + (eta1 - eta2)**2.)**0.5
+
+class eFEXNTupleLoader():
+    def __init__(self, filename):
+        self.tfile = ROOT.TFile(filename)
+        self.tree = self.tfile.Get("data;1")
+
+    def entries(self):
+        for each_entry in self.tree:
+            entry_dict = {}
+            entry_dict["truth_e_ET"] = np.asarray(each_entry.truth_e_ET)/1000.
+            entry_dict["truth_e_phi"] = np.asarray(each_entry.truth_e_phi)
+            entry_dict["truth_e_eta"] = np.asarray(each_entry.truth_e_eta)
+            entry_dict["eg_eta"] = np.asarray(each_entry.eg_eta) * 0.1 #+ 0.05
+            entry_dict["eg_phi"] = np.asarray(each_entry.eg_phi) * math.pi/32. #+ math.pi / 64# - math.pi)
+            entry_dict["eg_ET"] = np.asarray(each_entry.eg_ET)/1000.
+            entry_dict["eg_wstotnum"] = np.asarray(each_entry.eg_wstotnum)
+            entry_dict["eg_wstotden"] = np.asarray(each_entry.eg_wstotden)
+            entry_dict["eg_rhadnum"] = np.asarray(each_entry.eg_wstotnum)
+            entry_dict["eg_rhadden"] = np.asarray(each_entry.eg_wstotden)
+            entry_dict["eg_retanum"] = np.asarray(each_entry.eg_wstotnum)
+            entry_dict["eg_retaden"] = np.asarray(each_entry.eg_wstotden)
+            entry_dict["eg_haveseed"] = np.asarray(each_entry.eg_haveseed).astype(dtype=bool)
+            entry_dict["eg_nTOBs"] = int(each_entry.eg_nTOBs)
+            
+            entry_dict["truth_tauvisible_ET"] = np.asarray(each_entry.truth_tauvisible_ET)/1000.
+            entry_dict["truth_tauvisible_phi"] = np.asarray(each_entry.truth_tauvisible_phi)
+            entry_dict["truth_tauvisible_eta"] = np.asarray(each_entry.truth_tauvisible_eta)
+
+            entry_dict["eg_tauOregon_Et"] = np.asarray(each_entry.eg_tauOregon_Et)/1000.
+            entry_dict["eg_tauOregon_Iso"] = np.asarray(each_entry.eg_tauOregon_Iso)
+            entry_dict["eg_tauTLV_Et"] = np.asarray(each_entry.eg_tauTLV_Et)/1000.
+            entry_dict["eg_tauTLV_Iso"] = np.asarray(each_entry.eg_tauTLV_Iso)
+            # print(entry_dict["truth_e_phi"][0], entry_dict["truth_e_eta"][0])
+            # i = np.argmax(entry_dict["eg_ET"])
+            # print(entry_dict["eg_phi"][i], entry_dict["eg_eta"][i])
+            yield eFEXAnalyzer(entry_dict)
+
+    def __len__(self):
+        return self.tree.GetEntries() - 1
+
+class eFEXAnalyzer():
+    def __init__(self, inputs):
+        self.classtype = "e"
+        for key, value in inputs.items():
+            setattr(self, key, value)
+
+    def set_class_type(self, inputs):
+        self.classtype = inputs
+
+    def get_eg_matchedtob_id(self):
+        output = []
+        if self.classtype == "e":
+            for i_e in range(len(self.truth_e_ET)):
+                tob_id_tem = []
+                for i_tob in range(self.eg_nTOBs):
+                    # TODO et selection
+                    if self.eg_ET[i_tob] < 15.:
+                        continue
+                    if delta_R(self.truth_e_eta[i_e], self.truth_e_phi[i_e], self.eg_eta[i_tob], self.eg_phi[i_tob]) > 0.12:
+                        continue
+                    tob_id_tem.append(i_tob)
+                output.append(tob_id_tem)
+        if self.classtype == "tau":
+            for i_e in range(len(self.truth_tauvisible_ET)):
+                tob_id_tem = []
+                for i_tob in range(self.eg_nTOBs):
+                    # TODO et selection
+                    # if self.truth_tauvisible_ET[i_tob] < 12.:
+                    #     continue
+                    if delta_R(self.truth_tauvisible_eta[i_e], self.truth_tauvisible_phi[i_e], self.eg_eta[i_tob], self.eg_phi[i_tob]) > 0.12:
+                        continue
+                    tob_id_tem.append(i_tob)
+                output.append(tob_id_tem)
+        return output
+
+    def leading_l_id(self):
+        if self.classtype == "e":
+            return np.argmax(self.truth_e_ET)
+        if self.classtype == "tau":
+            if len(self.truth_tauvisible_ET) == 0:
+                return None
+            return np.argmax(self.truth_tauvisible_ET)
+
+
+    def is_in_crack(self, i_e):
+        if self.classtype == "e":
+            return (abs(self.truth_e_eta[i_e]) > 1.375 and abs(self.truth_e_eta[i_e]) < 1.52)
+        if self.classtype == "tau":
+            return (abs(self.truth_tauvisible_eta[i_e]) > 1.375 and abs(self.truth_tauvisible_eta[i_e]) < 1.52)
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/makeegammaturnon.py b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/makeegammaturnon.py
new file mode 100644
index 0000000000000000000000000000000000000000..852c90e0c556eb22f5942ccf96d2514623a68f2c
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/makeegammaturnon.py
@@ -0,0 +1,94 @@
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+
+#***************************************************************************
+#                           makeplots.py  -  
+#                              -------------------
+#     begin                : 28 03 2020
+#     email                : tong.qiu@cern.ch
+#  **************************************************************************
+from __future__ import print_function
+from __future__ import division
+import numpy as np
+from eFEXNTuple import *
+from plotlib import *
+import sys
+
+def rebin(binning, data):
+    hist, edge = np.histogram(data, binning)
+    newbin = [edge[0]]
+    total_i = 0
+    for i in range(len(hist)):
+        total_i += hist[i]
+        if total_i > 0:
+            newbin.append(edge[i+1])
+            total_i = 0
+    newbin[-1] = binning[-1]
+    return newbin
+
+def rebin2(binning, data1, data2):
+    hist1, edge = np.histogram(data1, binning)
+    hist2, edge = np.histogram(data2, binning)
+    newbin = [edge[0]]
+    total_1 = 0
+    total_2 = 0
+    for i in range(len(hist1)):
+        total_1 += hist1[i]
+        total_2 += hist2[i]
+        if total_1 > 0 and total_2 > 0:
+            newbin.append(edge[i+1])
+            total_1 = 0
+            total_2 = 0
+    newbin[-1] = binning[-1]
+    return newbin
+
+def turn_on_curve(all_data, selected_data, bins):
+    bins = rebin(bins, all_data)
+    hist_all, edges = np.histogram(all_data, bins)
+    hist_selected, edges = np.histogram(selected_data, bins)
+    bin_centre = [(edges[i] + edges[i+1])/2. for i in range(len(edges)-1)]
+    hist_height = hist_selected / hist_all
+    hist_error = ((hist_selected**0.5 / hist_all)**2. + (hist_all**0.5 * hist_selected / hist_all**2.)**2.)**0.5
+    return (hist_height, bin_centre, hist_error)
+
+def main(path):
+    myntuple = eFEXNTupleLoader(path)
+    all_e_ET = []
+    selected_e_ET = []
+    for each in myntuple.entries():
+        each.set_class_type("e")
+        if each.is_in_crack(each.leading_l_id()):
+            continue
+        if abs(each.truth_e_eta[each.leading_l_id()]) > 2.3:
+            continue
+        all_e_ET.append(each.truth_e_ET[each.leading_l_id()])
+        matched_tobs = each.get_eg_matchedtob_id()[each.leading_l_id()]
+        selected = False
+        for i in matched_tobs:
+            if not each.eg_haveseed[i]:
+                continue
+            if each.eg_ET[i] <= 22:
+                continue
+            #if 0.025*(each.eg_wstotnum[i]/each.eg_wstotden[i])**0.5 < 0.045:
+            selected = True
+            break
+        if selected:
+            selected_e_ET.append(each.truth_e_ET[each.leading_l_id()])
+
+    hist_height, bin_centre, hist_error = turn_on_curve(all_e_ET, selected_e_ET, range(0,100,5))
+    histplot([bin_centre], [hist_height], [hist_error], errorbar_limit=1, filename="egammatrunon")
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 2:
+        print("Error: too many arguments")
+        print("Example: python makeplots.py PATH/TO/INPUT")
+        exit(1)
+    if len(sys.argv) == 1:
+        print("Error: need the path to the input file")
+        print("Example: python makeplots.py PATH/TO/INPUT")
+        print("Info: Using default input file path")
+        inputfile = "myfile.root"
+    else:
+        inputfile = sys.argv[1]
+    main(inputfile)
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/maketauturnon.py b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/maketauturnon.py
new file mode 100644
index 0000000000000000000000000000000000000000..22c471e62aef885199c5af964d0d1d13f142e3a7
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/maketauturnon.py
@@ -0,0 +1,119 @@
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+
+#***************************************************************************
+#                           makeplots.py  -  
+#                              -------------------
+#     begin                : 28 03 2020
+#     email                : tong.qiu@cern.ch
+#  **************************************************************************
+from __future__ import print_function
+from __future__ import division
+import numpy as np
+from eFEXNTuple import *
+from plotlib import *
+import sys
+
+def rebin(binning, data):
+    hist, edge = np.histogram(data, binning)
+    newbin = [edge[0]]
+    total_i = 0
+    for i in range(len(hist)):
+        total_i += hist[i]
+        if total_i > 0:
+            newbin.append(edge[i+1])
+            total_i = 0
+    newbin[-1] = binning[-1]
+    return newbin
+
+def rebin2(binning, data1, data2):
+    hist1, edge = np.histogram(data1, binning)
+    hist2, edge = np.histogram(data2, binning)
+    newbin = [edge[0]]
+    total_1 = 0
+    total_2 = 0
+    for i in range(len(hist1)):
+        total_1 += hist1[i]
+        total_2 += hist2[i]
+        if total_1 > 0 and total_2 > 0:
+            newbin.append(edge[i+1])
+            total_1 = 0
+            total_2 = 0
+    newbin[-1] = binning[-1]
+    return newbin
+
+def turn_on_curve(all_data, selected_data, bins):
+    bins = rebin(bins, all_data)
+    hist_all, edges = np.histogram(all_data, bins)
+    hist_selected, edges = np.histogram(selected_data, bins)
+    bin_centre = [(edges[i] + edges[i+1])/2. for i in range(len(edges)-1)]
+    hist_height = hist_selected / hist_all
+    hist_error = ((hist_selected**0.5 / hist_all)**2. + (hist_all**0.5 * hist_selected / hist_all**2.)**2.)**0.5
+    return (hist_height, bin_centre, hist_error)
+
+def main(path):
+    myntuple = eFEXNTupleLoader(path)
+    all_l_ET = []
+    selected_l_ET_TLV = []
+    selected_l_eta_TLV = []
+    selected_l_ET_Oregon = []
+    selected_l_eta_Oregon = []
+    all_l_eta = []
+    for each in myntuple.entries():
+        each.set_class_type("tau")
+        if each.leading_l_id() is None:
+            continue
+        # if len(each.truth_l_ET)==0:
+        #     continue
+        if each.is_in_crack(each.leading_l_id()):
+            continue
+        if abs(each.truth_tauvisible_eta[each.leading_l_id()]) > 2.3:
+            continue
+        # if abs(each.truth_tauvisible_ET[each.leading_l_id()] <= 40):
+        #     continue
+        all_l_ET.append(each.truth_tauvisible_ET[each.leading_l_id()])
+        all_l_eta.append(each.truth_tauvisible_eta[each.leading_l_id()])
+        matched_tobs = each.get_eg_matchedtob_id()[each.leading_l_id()]
+        tlv_selected = False
+        oregon_selected = False
+        for i in matched_tobs:
+            if each.eg_tauTLV_Et[i] <= 12:
+                continue
+            if each.eg_tauTLV_Iso[i] < 0.66 and each.eg_tauTLV_Et[i] <= 15:
+                continue
+            tlv_selected = True
+            break
+        for i in matched_tobs:
+            if each.eg_tauOregon_Et[i] <= 12:
+                continue
+            if each.eg_tauOregon_Iso[i] < 0.66 and each.eg_tauOregon_Et[i] <= 15:
+                continue
+            oregon_selected = True
+            break
+        if tlv_selected:
+            selected_l_ET_TLV.append(each.truth_tauvisible_ET[each.leading_l_id()])
+            #selected_l_eta_TLV.append(each.truth_tauvisible_eta[each.leading_l_id()])
+        if oregon_selected:
+            selected_l_ET_Oregon.append(each.truth_tauvisible_ET[each.leading_l_id()])
+            #selected_l_eta_Oregon.append(each.truth_tauvisible_eta[each.leading_l_id()])
+    hist_height, bin_centre, hist_error = turn_on_curve(all_l_ET, selected_l_ET_TLV, range(0,100,5))
+    histplot([bin_centre], [hist_height], [hist_error], errorbar_limit=1, filename="tautlvtrunon")
+    hist_height, bin_centre, hist_error = turn_on_curve(all_l_ET, selected_l_ET_Oregon, range(0,100,5))
+    histplot([bin_centre], [hist_height], [hist_error], errorbar_limit=1, filename="tauoregontrunon")
+    # hist_height, bin_centre, hist_error = turn_on_curve(all_l_eta, selected_l_eta, np.linspace(-2.3,2.3,10))
+    # histplot([bin_centre], [hist_height], [hist_error], errorbar_limit=1, filename="eta", xlabel="eta")
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 2:
+        print("Error: too many arguments")
+        print("Example: python makeplots.py PATH/TO/INPUT")
+        exit(1)
+    if len(sys.argv) == 1:
+        print("Error: need the path to the input file")
+        print("Example: python makeplots.py PATH/TO/INPUT")
+        print("Info: Using default input file path")
+        inputfile = "myfile.root"
+    else:
+        inputfile = sys.argv[1]
+    main(inputfile)
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/plotlib.py b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/plotlib.py
new file mode 100644
index 0000000000000000000000000000000000000000..77172500ccefb545e3db7984862c51a8839bb277
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/script/plotlib.py
@@ -0,0 +1,72 @@
+#  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+
+#***************************************************************************
+#                           plotlib.py  -  
+#                              -------------------
+#     begin                : 28 03 2020
+#     email                : tong.qiu@cern.ch
+#  **************************************************************************
+from __future__ import division
+import matplotlib
+matplotlib.use('Agg')
+import math
+import matplotlib.pyplot as plt
+import numpy as np
+import copy
+
+def histplot(data_x, data_y, error=None, label=None, **kwargs):
+    settings = {
+        "xlabel" : r"$p_T\:[GeV]$",
+        "ylabel": 'Efficiency',
+        "title1": r"ATLAS",
+        "title1_1": r"Simulation",
+        "title2": r"$\sqrt{s}=13\:TeV$",
+        "filename": "trunontest",
+        "log_y":False,
+        "norm":False,
+        "scale":1,
+        "upper_y": 1.7,
+        "errorbar_limit": None,
+        }
+    for each_key in kwargs.items():
+        settings[each_key[0]] = kwargs[each_key[0]]
+    plt.figure(figsize=(8, 6))
+    remove_label = False
+    if label is None:
+        remove_label = True
+        label = ["a"] * len(data_x)
+    for i in range(len(data_x)):
+        if error is not None:
+            if settings["errorbar_limit"] is not None:
+                allerror = []
+                for each_error, each_yi in zip(error[i], data_y[i]):
+                    uperror = each_error
+                    if each_yi + each_error > settings["errorbar_limit"]:
+                        uperror = settings["errorbar_limit"] - each_yi
+                    allerror.append([each_error, uperror])
+            else:
+                allerror = error[i]
+            style = '.-'
+            if len(data_x) == 1:
+                style = 'k.-'
+            plt.errorbar(data_x[i], data_y[i], yerr=np.array(allerror).T, label=label[i], fmt=style)
+        else:
+            plt.plot(data_x[i], data_y[i], label=label[i])
+    ax1 = plt.gca()
+
+    plt.legend(loc='upper right', prop={'size': 25}, frameon=False)
+    if remove_label:
+        ax1.get_legend().remove()
+
+    ax1.set_ylim([0, max([y for x in data_y for y in x])* settings["upper_y"]])
+    ax1.text(0.05, 1.55 / 1.7, settings['title1'], fontsize=25, transform=ax1.transAxes, style='italic', fontweight='bold')
+    ax1.text(0.28, 1.55/ 1.7, settings['title1_1'], fontsize=25, transform=ax1.transAxes)
+    ax1.text(0.05, 1.40 / 1.7, settings['title2'], fontsize=23, transform=ax1.transAxes)
+
+    plt.tick_params(labelsize=16)
+    plt.tick_params(labelsize=16)
+    plt.ylabel(settings['ylabel'], fontsize=20)
+    plt.xlabel(settings['xlabel'], fontsize=20)
+    plt.savefig(settings['filename'] + '.pdf', bbox_inches='tight')
+    plt.close()
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/share/eFEXDriverJobOptions.py b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/share/eFEXDriverJobOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf9e03999da759ed36c86621b544c5956ec24bbc
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/share/eFEXDriverJobOptions.py
@@ -0,0 +1,60 @@
+#jps.AthenaCommonFlags.AccessMode = "POOLAccess" # use POOL read mode because reading calocells
+#svcMgr.EventSelector.InputCollections = jps.AthenaCommonFlags.FilesInput()
+from AthenaCommon.GlobalFlags  import globalflags
+import AthenaPoolCnvSvc.ReadAthenaPool
+
+if type(theApp).__name__ == "fakeAppMgr": theApp.initialize() #this line cuts off pathena when joboption parsing ... since all outputs now declared
+
+#from RecExConfig import AutoConfiguration
+#AutoConfiguration.ConfigureSimulationOrRealData()
+#AutoConfiguration.ConfigureGeo()
+#AutoConfiguration.ConfigureConditionsTag()
+#from AthenaCommon.DetFlags import DetFlags
+#DetFlags.detdescr.all_setOff()
+#DetFlags.detdescr.Calo_setOn()
+#include("RecExCond/AllDet_detDescr.py")
+
+#include( "CaloConditions/CaloConditions_jobOptions.py" )
+include( "LArDetDescr/LArDetDescr_joboptions.py" )
+
+
+include( "RegistrationServices/IOVRegistrationSvc_jobOptions.py" )
+
+IOVBeginRun   = IOVRunNumberMin
+IOVEndRun     = IOVRunNumberMax
+IOVBeginLB = IOVLBNumberMin
+IOVEndLB   = IOVLBNumberMax
+
+import RegistrationServices.IOVRegistrationSvc
+regSvc = svcMgr.IOVRegistrationSvc
+
+
+#svcMgr.IOVDbSvc.DBInstance=""
+
+if "GlobalTag" not in dir():
+    GlobalTag     = 'OFLCOND-CSC-00-01-00' #Sadly event his doesn't work for the 14 TeV jetjet sample 'OFLCOND-MC15c-SDR-14-02' #This works for 13 TeV 'OFLCOND-CSC-00-01-00'    #No idea what this is: COMCOND-BLKPST-004-05'
+
+#svcMgr.IOVDbSvc.GlobalTag = GlobalTag
+
+svcMgr.IOVDbSvc.GlobalTag=globalflags.ConditionsTag()
+
+# configure detector description from metadata in input file
+from RecExConfig import AutoConfiguration
+AutoConfiguration.ConfigureSimulationOrRealData()
+AutoConfiguration.ConfigureGeo()
+AutoConfiguration.ConfigureConditionsTag()
+from AthenaCommon.DetFlags import DetFlags
+DetFlags.detdescr.all_setOff()
+DetFlags.detdescr.Calo_setOn()
+include("RecExCond/AllDet_detDescr.py")
+
+svcMgr += CfgMgr.THistSvc()
+#svcMgr.THistSvc.Output += ["ISO DATAFILE='tobIso.root' OPT='RECREATE'"]
+svcMgr.THistSvc.Output += ["ANALYSIS DATAFILE='myfile.root' OPT='RECREATE'"]
+#######################################################
+log.info("==========================================================")
+log.info("Scheduling eFEXDriver")
+athAlgSeq += CfgMgr.LVL1__eFEXDriver('MyeFEXDriver')
+athAlgSeq += CfgMgr.LVL1__eFEXNtupleWriter('MyeFEXNtupleWriter')
+log.info("==========================================================")
+#######################################################
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/components/eFEXDriver_entries.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/components/eFEXDriver_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..93d20d072eeb09ea2fa8d18d2c2e7d4da857a76e
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/components/eFEXDriver_entries.cxx
@@ -0,0 +1,36 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "L1CaloFEXSim/eFEXDriver.h"
+#include "L1CaloFEXSim/eFEXSysSim.h"
+#include "L1CaloFEXSim/eFEXSim.h"
+#include "L1CaloFEXSim/eFEXFPGA.h"
+#include "L1CaloFEXSim/eFEXtauAlgo.h"
+#include "L1CaloFEXSim/eFEXegAlgo.h"
+#include "L1CaloFEXSim/eFEXNtupleWriter.h"
+
+//#include "GaudiKernel/DeclareFactoryEntries.h"
+
+using namespace LVL1;
+
+DECLARE_COMPONENT(eFEXDriver)
+DECLARE_COMPONENT(eFEXSysSim)
+DECLARE_COMPONENT(eFEXSim)
+DECLARE_COMPONENT(eTowerBuilder)
+DECLARE_COMPONENT(eSuperCellTowerMapper)
+DECLARE_COMPONENT(eFEXFPGA)
+DECLARE_COMPONENT(eFEXtauAlgo)
+DECLARE_COMPONENT(eFEXegAlgo)
+DECLARE_COMPONENT(eFEXNtupleWriter)
+//Notes:
+//
+//1. The argument to the DECLARE_FACTORY_ENTRIES(XXX) is the name of the
+//   component library (libXXX.so).
+//2. Each Algorithm that is contained in the library should be declared
+//   by the DECLARE_ALGORITHM() statement.
+//3. Each Service that is contained in the library should be declared
+//   by the DECLARE_SERVICE() statement.
+//
+// See Athena User Guide for more information
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/components/eFEXDriver_load.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/components/eFEXDriver_load.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ee83a8def0f26d840db8fb8f7a2a51877992d5d2
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/components/eFEXDriver_load.cxx
@@ -0,0 +1,15 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES(eFEXDriver)
+LOAD_FACTORY_ENTRIES(eFEXNtupleWriter)
+  //Notes:
+  //
+  //1. The argument to the LOAD_FACTORY_ENTRIES() is the name of the
+  //   component library (libXXX.so).
+  //
+  // See Athena User Guide for more information
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXCompression.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXCompression.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cb6c5f232056ed3dd1c50beb0ed8a4b26ce721ce
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXCompression.cxx
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+/***************************************************************************
+                          eFEXCompression.cxx  -  description
+                             -------------------
+    begin                : 07-02-2019
+    email                : Alan.Watson@cern.ch antonio.jacques.costa@cern.ch
+ ***************************************************************************/
+
+#include "L1CaloFEXSim/eFEXCompression.h"
+
+namespace LVL1 {
+
+const int eFEXCompression::s_steps[] = {25, 50, 100, 200, 400, 102400};
+const int eFEXCompression::s_minET[] = {-750, 1600, 6400, 25600, 102400, 200000};
+const int eFEXCompression::s_minCode[] = {2, 96, 192, 384, 768, 1012};
+
+unsigned int eFEXCompression::Compress(int Et) {
+
+  // Check for overflow
+  if (Et >= s_maxET) return s_LArOverflow;
+ 
+  // Find which range the ET value is in
+  int range = -1;
+  for (unsigned int i = 0; i < s_nRanges; i++) {
+    if (Et < s_minET[i]) break;
+    range = i;
+  }
+
+  // Calculate code
+  unsigned int code = 0;
+
+  if (range < 0) {
+    // Below minimum value
+    code = s_LArUnderflow; 
+  }
+  else {
+    // Lies inside one of the value ranges
+    int steps = (Et - s_minET[range])/s_steps[range];
+    code = s_minCode[range] + steps;
+  }
+
+  return code;
+}
+
+int eFEXCompression::Expand(unsigned int code) {
+
+  // Deal with special codes first:
+  if (code == s_NoData)  return 0;
+  if (code == s_LArInvalid || code == s_LArReserved || code > s_LArMaxCode) return s_error; 
+  if (code == s_LArOverflow || code == s_LArSaturated) return s_maxET;
+
+  /** Now expand code into an ET value.
+      Start by finding what range the code is in */
+  int range = 0;
+  for (unsigned int i = 0; i < s_nRanges-1; ++i) {
+    if (code < (unsigned int)s_minCode[i+1]) break;
+    range++;
+  }
+  /// Now expand the value
+  int Et = s_minET[range] + (code-s_minCode[range])*s_steps[range];
+  
+  return Et;
+}
+
+
+unsigned int eFEXCompression::Threshold(unsigned int code, int threshold) {
+
+  /// Convert threshold into a compressed code
+  unsigned int cut = eFEXCompression::Compress(threshold);
+
+  /// Zero code if < threshold
+  if (code < cut) code = 0;
+
+  return code;
+}
+
+
+unsigned int eFEXCompression::Linearize(unsigned int code, int threshold) {
+
+  /// Apply the threshold. Since eFEX ET is positive, minimum threshold is 0.
+  if (threshold < 0) threshold = 0;
+  code = eFEXCompression::Threshold(code, threshold);
+
+  /// Expand the ET value
+  int Et = eFEXCompression::Expand(code);
+
+  // Check for overflow
+  if (Et >= s_maxET) return s_eFEXOverflow;
+
+  /// Convert to eFEX digit scale
+  unsigned int eFexET = Et/s_eFEXstep;
+  return eFexET;
+}
+
+} // end of namespace bracket
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXDriver.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXDriver.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d46fb3d1aa2811d383ca8190b55ceb7b2dba19e1
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXDriver.cxx
@@ -0,0 +1,170 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#undef NDEBUG
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+#include "xAODTrigL1Calo/TriggerTowerContainer.h"
+
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerBuilder.h"
+#include "L1CaloFEXSim/eFEXDriver.h"
+
+#include "L1CaloFEXSim/eSuperCellTowerMapper.h"
+
+#include "L1CaloFEXSim/eFEXSim.h"
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+#include "L1CaloFEXSim/eFEXegTOB.h"
+
+#include "TROOT.h"
+#include "TH1.h"
+#include "TH1F.h"
+#include "TPad.h"
+#include "TCanvas.h"
+
+#include "StoreGate/WriteHandle.h"
+#include "StoreGate/ReadHandle.h"
+
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+#include <cassert>
+#include "SGTools/TestStore.h"
+
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ITHistSvc.h"
+
+#include <ctime>
+
+#define DEBUG_VHB 1
+
+
+namespace LVL1 {
+
+  eFEXDriver::eFEXDriver(const std::string& name, ISvcLocator* pSvcLocator)
+    :  AthAlgorithm(name, pSvcLocator)//AthReentrantAlgorithm(name, pSvcLocator)
+  { 
+  
+  }
+
+
+ eFEXDriver::~eFEXDriver()
+{
+  ATH_MSG_DEBUG("Destroying " << name() << "...");
+}
+
+
+StatusCode eFEXDriver::initialize()
+{
+
+  m_numberOfEvents = 1;
+
+  ServiceHandle<ITHistSvc> histSvc("THistSvc","");
+  StatusCode scHist = histSvc.retrieve();
+  if (scHist ==  StatusCode::FAILURE) {ATH_MSG_ERROR("Failed to retrieve THistSvc"); }
+
+  //Reta
+  TH1F* hReta = new TH1F("Reta", "Reta",20,0,1);
+  hReta->GetXaxis()->SetTitle("TObs Reta");
+  hReta->GetYaxis()->SetTitle("Events");
+  
+  StatusCode scReg = histSvc->regHist("/ISO/Reta", hReta); 
+  if (scReg ==  StatusCode::FAILURE) {ATH_MSG_ERROR("Failed to define stream"); }
+
+
+  ATH_CHECK( m_eTowerBuilderTool.retrieve() );
+
+  ATH_CHECK( m_eSuperCellTowerMapperTool.retrieve() );
+
+  ATH_CHECK( m_eFEXSysSimTool.retrieve() );
+
+  ATH_CHECK( m_eTowerContainerSGKey.initialize() );
+
+  //ATH_CHECK( m_eFEXOutputCollectionSGKey.initialize() );
+
+  return StatusCode::SUCCESS;
+
+}
+
+
+StatusCode eFEXDriver::finalize()
+{
+  ATH_MSG_DEBUG("Finalizing " << name() << "...");
+  return StatusCode::SUCCESS;
+}
+
+
+  StatusCode eFEXDriver::execute(/*const EventContext& ctx*/) //const
+{
+
+  ATH_MSG_DEBUG("Executing " << name() << ", processing event number " << m_numberOfEvents );
+
+  // OLD DIMA STUFF---------------------- Maybe useful in the future again
+  //if (fabsf((*cell)->eta()) > 2.55) continue;
+  //if (!((*cell)->provenance() & 0x40)) continue; // BCID cut
+  //// if (!((*cell)->provenance() & 0x200)) continue;
+  //// 8192 & 0x40 = 0
+  //// 8256 & 0x40 = 64
+  //// 8704 & 0x40 = 0
+  //// 8768 & 0x40 = 64
+
+  // STEP 0 - Make a fresh local eTowerContainer
+  //eTowerContainer* local_eTowerContainerRaw = new eTowerContainer();
+  std::unique_ptr<eTowerContainer> local_eTowerContainerRaw = std::make_unique<eTowerContainer>();
+
+  // STEP 1 - Do some monitoring (code to exported in the future to another algorithm accessing only StoreGate and not appearing in this algorithm)
+  eFEXOutputCollection* my_eFEXOutputCollection = new eFEXOutputCollection();
+  bool savetob = true;
+  if(savetob)
+  {
+    StatusCode sctob = evtStore()->record(my_eFEXOutputCollection,"eFEXOutputCollection");
+    if(sctob == StatusCode::SUCCESS){}
+    else if (sctob == StatusCode::FAILURE){ATH_MSG_ERROR("Event " << m_numberOfEvents << " , Failed to put eFEXOutputCollection into Storegate.");}
+    
+    /*
+    SG::WriteHandle<eFEXOutputCollection> eFEXOutputCollectionSG(m_eFEXOutputCollectionSGKey,ctx);
+    ATH_CHECK(eFEXOutputCollectionSG.record(std::make_unique<eFEXOutputCollection>()));
+    */
+  }
+
+  // STEP 2 - Make some eTowers and fill the local container
+  ATH_CHECK( m_eTowerBuilderTool.retrieve() );
+  m_eTowerBuilderTool->init(local_eTowerContainerRaw);
+  local_eTowerContainerRaw->clearContainerMap();
+  local_eTowerContainerRaw->fillContainerMap();
+
+  // STEP 3 - Do the supercell-tower mapping - put this information into the eTowerContainer
+  ATH_CHECK( m_eSuperCellTowerMapperTool.retrieve() );
+  ATH_CHECK(m_eSuperCellTowerMapperTool->AssignSuperCellsToTowers(local_eTowerContainerRaw));
+  ATH_CHECK(m_eSuperCellTowerMapperTool->AssignTriggerTowerMapper(local_eTowerContainerRaw));
+
+  // STEP 4 - Write the completed eTowerContainer into StoreGate (move the local copy in memory)
+  SG::WriteHandle<LVL1::eTowerContainer> eTowerContainerSG(m_eTowerContainerSGKey/*, ctx*/);
+  //std::unique_ptr<LVL1::eTowerContainer> my_eTowerContainerRaw(local_eTowerContainerRaw);
+  ATH_CHECK(eTowerContainerSG.record(std::move(/*my_eTowerContainerRaw*/local_eTowerContainerRaw)));
+
+  // STEP 5 - Set up the eFEXSysSim
+  ATH_CHECK( m_eFEXSysSimTool.retrieve() );
+  m_eFEXSysSimTool->init();
+
+  // STEP 6 - Run THE eFEXSysSim
+  ATH_CHECK(m_eFEXSysSimTool->execute());
+
+  // STEP 7 - Close and clean the event  
+  m_eFEXSysSimTool->cleanup();
+  m_eSuperCellTowerMapperTool->reset();
+  m_eTowerBuilderTool->reset();
+
+  ATH_MSG_DEBUG("Executed " << name() << ", closing event number " << m_numberOfEvents );
+
+  m_numberOfEvents++;
+
+  return StatusCode::SUCCESS;
+}
+  
+  
+} // end of LVL1 namespace
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..94e6609d10348be5558781bab26f46309c8c7e7b
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx
@@ -0,0 +1,205 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXFPGA  -  description
+//                              -------------------
+//     begin                : 15 10 2019
+//     email                : jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+#include "L1CaloFEXSim/eFEXFPGA.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "L1CaloFEXSim/eFEXegAlgo.h"
+#include "L1CaloFEXSim/eFEXegTOB.h"
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+#include "L1CaloFEXSim/eFEXtauAlgo.h"
+#include "L1CaloFEXSim/eFEXtauTOB.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include <vector>
+#include "TH1F.h"
+#include "StoreGate/WriteHandle.h"
+#include "StoreGate/ReadHandle.h"
+#include "SGTools/TestStore.h"
+
+
+namespace LVL1 {
+
+  // default constructor for persistency
+
+eFEXFPGA::eFEXFPGA(const std::string& type,const std::string& name,const IInterface* parent):
+  AthAlgTool(type,name,parent)
+{
+  declareInterface<IeFEXFPGA>(this);
+}
+  
+    
+  /** Destructor */
+  eFEXFPGA::~eFEXFPGA()
+  {
+  }
+
+//================ Initialisation =================================================
+  
+StatusCode eFEXFPGA::initialize()
+{
+
+  ATH_CHECK(m_eFEXFPGA_eTowerContainerKey.initialize());
+  //ATH_CHECK(m_eFEXFPGA_eFEXOutputCollectionKey.initialize());
+  return StatusCode::SUCCESS;
+}
+  
+
+StatusCode eFEXFPGA::init(int id, int efexid)
+{
+  m_id = id;
+  m_efexid = efexid;
+
+  return StatusCode::SUCCESS;
+
+}
+
+void eFEXFPGA::reset(){
+
+  m_id = -1;
+  m_efexid = -1;
+
+}
+
+StatusCode eFEXFPGA::execute(){
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXFPGA_eTowerContainer(m_eFEXFPGA_eTowerContainerKey/*,ctx*/);
+  if(!jk_eFEXFPGA_eTowerContainer.isValid()){
+    ATH_MSG_FATAL("Could not retrieve jk_eFEXFPGA_eTowerContainer " << m_eFEXFPGA_eTowerContainerKey.key() );
+    return StatusCode::FAILURE;
+  }
+    
+  eFEXOutputCollection* eFEXOutputs;
+
+  // To be replaced soon but left here commented for information
+  /*
+  SG::ReadHandle<eFEXOutputCollection> jk_eFEXFPGA_eFEXOutputCollection(m_eFEXFPGA_eFEXOutputCollectionKey,ctx);
+  if(!jk_eFEXFPGA_eFEXOutputCollection.isValid()){
+    ATH_MSG_FATAL("Could not retrieve jk_eFEXFPGA_eFEXOutputCollection " << m_eFEXFPGA_eFEXOutputCollectionKey.key() );
+    return StatusCode::FAILURE;
+  }
+  */
+  
+  StatusCode sc_tobs = evtStore()->retrieve(eFEXOutputs, "eFEXOutputCollection");
+  if(sc_tobs == StatusCode::SUCCESS){ }
+  else if(sc_tobs == StatusCode::FAILURE) {ATH_MSG_DEBUG("\n==== eFEXegAlgo ========= Failed to find eFEXOutputCollection in eFEXFPGA"); }
+  
+
+  for(int ieta = 1; ieta < 5; ieta++) {
+    for(int iphi = 1; iphi < 9; iphi++) {
+      int tobtable[3][3]={
+        {m_eTowersIDs[iphi-1][ieta-1], m_eTowersIDs[iphi-1][ieta], m_eTowersIDs[iphi-1][ieta+1]},
+        {m_eTowersIDs[iphi][ieta-1], m_eTowersIDs[iphi][ieta], m_eTowersIDs[iphi][ieta+1]},
+        {m_eTowersIDs[iphi+1][ieta-1], m_eTowersIDs[iphi+1][ieta], m_eTowersIDs[iphi+1][ieta+1]},
+      };
+
+      ATH_CHECK( m_eFEXegAlgoTool.retrieve() );
+  
+      ATH_CHECK( m_eFEXegAlgoTool->safetyTest() );
+      m_eFEXegAlgoTool->setup(tobtable);
+
+      // temporarily(?) removed for debugging
+      //if (eFEXFPGA_egAlgo->haveSeed() == false) continue;
+      
+      std::vector<unsigned int> RetaND = m_eFEXegAlgoTool->getReta();
+      std::vector<unsigned int> RhadND; m_eFEXegAlgoTool->getRhad(RhadND);
+      
+      std::unique_ptr<eFEXegTOB> tmp_tob = m_eFEXegAlgoTool->geteFEXegTOB();
+      
+      tmp_tob->setFPGAID(m_id);
+      // TODO tmp_tob->.setEFEXID(xxx);
+      tmp_tob->setEta(ieta);
+      tmp_tob->setPhi(iphi);
+
+      // for plotting
+      eFEXOutputs->addValue_eg("WstotNum", tmp_tob->getWstotNum());
+      eFEXOutputs->addValue_eg("WstotDen", tmp_tob->getWstotDen());
+      eFEXOutputs->addValue_eg("RetaNum", tmp_tob->getRetaNum());
+      eFEXOutputs->addValue_eg("RetaDen", tmp_tob->getRetaDen());
+      eFEXOutputs->addValue_eg("RhadNum", tmp_tob->getRhadNum());
+      eFEXOutputs->addValue_eg("RhadDen", tmp_tob->getRhadDen());
+      eFEXOutputs->addValue_eg("haveSeed", m_eFEXegAlgoTool->haveSeed());
+      eFEXOutputs->addValue_eg("Et", m_eFEXegAlgoTool->getET());
+      float eta = 9999;
+      m_eFEXegAlgoTool->getRealEta(eta);
+      eFEXOutputs->addValue_eg("eta", eta);
+      float phi = 9999;
+      m_eFEXegAlgoTool->getRealPhi(phi);
+      eFEXOutputs->addValue_eg("phi", phi);
+      unsigned int em_et = 9999; 
+      m_eFEXegAlgoTool->getCoreEMTowerET(em_et);
+      eFEXOutputs->addValue_eg("em", em_et);
+      unsigned int had_et = 9999;
+      m_eFEXegAlgoTool->getCoreHADTowerET(had_et);
+      eFEXOutputs->addValue_eg("had", had_et);
+      eFEXOutputs->fill_eg();
+
+    }
+  }
+
+  // =============== TAU =============
+  for(int ieta = 1; ieta < 5; ieta++)
+  {
+    for(int iphi = 1; iphi < 9; iphi++)
+    {
+      int tobtable[3][3]={
+        {m_eTowersIDs[iphi-1][ieta-1], m_eTowersIDs[iphi-1][ieta], m_eTowersIDs[iphi-1][ieta+1]},
+        {m_eTowersIDs[iphi][ieta-1], m_eTowersIDs[iphi][ieta], m_eTowersIDs[iphi][ieta+1]},
+        {m_eTowersIDs[iphi+1][ieta-1], m_eTowersIDs[iphi+1][ieta], m_eTowersIDs[iphi+1][ieta+1]},
+      };
+      
+      ATH_CHECK( m_eFEXtauAlgoTool.retrieve() );
+  
+      ATH_CHECK( m_eFEXtauAlgoTool->safetyTest() );
+      m_eFEXtauAlgoTool->setup(tobtable);
+
+      // for plotting
+      eFEXOutputs->addValue_tau("isCentralTowerSeed", m_eFEXtauAlgoTool->isCentralTowerSeed());
+      eFEXOutputs->addValue_tau("Et", m_eFEXtauAlgoTool->getEt());
+      eFEXOutputs->addValue_tau("Iso", m_eFEXtauAlgoTool->getIso());
+      
+      eFEXOutputs->fill_tau();
+
+      if (!m_eFEXtauAlgoTool->isCentralTowerSeed()){ continue; }
+
+    }
+  }
+
+  return StatusCode::SUCCESS;
+
+}
+
+void eFEXFPGA::SetTowersAndCells_SG(int tmp_eTowersIDs_subset[][6]){
+    
+  int rows = 10;
+  int cols = sizeof tmp_eTowersIDs_subset[0] / sizeof tmp_eTowersIDs_subset[0][0];
+  
+  std::copy(&tmp_eTowersIDs_subset[0][0], &tmp_eTowersIDs_subset[0][0]+(10*6),&m_eTowersIDs[0][0]);
+  
+  if(false){ //this prints out the eTower IDs that each FPGA is responsible for
+    ATH_MSG_DEBUG("\n==== eFEXFPGA ========= FPGA (" << m_id << ") IS RESPONSIBLE FOR eTOWERS :");
+    for (int thisRow=rows-1; thisRow>=0; thisRow--){
+      for (int thisCol=0; thisCol<cols; thisCol++){
+	if(thisCol != cols-1){ ATH_MSG_DEBUG("|  " << m_eTowersIDs[thisRow][thisCol] << "  "); }
+	else { ATH_MSG_DEBUG("|  " << m_eTowersIDs[thisRow][thisCol] << "  |"); }
+      }
+    }
+  }
+  
+}
+  
+} // end of namespace bracket
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXNtupleWriter.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXNtupleWriter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1faa0bf749dfba0f146511240cfa40ba8eb5c3df
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXNtupleWriter.cxx
@@ -0,0 +1,302 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXNtupleWriter.cxx  -  
+//                              -------------------
+//     begin                : 28 02 2020
+//     email                : tong.qiu@cern.ch
+//  **************************************************************************
+
+#include <L1CaloFEXSim/eFEXNtupleWriter.h>
+#include "StoreGate/StoreGateSvc.h"
+#include "L1CaloFEXSim/eFEXegTOB.h"
+#include "L1CaloFEXSim/eFEXtauAlgo.h"
+#include "L1CaloFEXSim/eFEXtauTOB.h"
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+#include <vector>
+#include "TTree.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include <memory>
+
+#include "xAODTruth/TruthEventContainer.h"
+#include "xAODTruth/TruthParticle.h"
+#include "xAODTruth/TruthVertex.h"
+#include "xAODTruth/TruthParticleContainer.h"
+#include "xAODJet/JetContainer.h"
+
+
+LVL1::eFEXNtupleWriter::eFEXNtupleWriter(const std::string& name, ISvcLocator* pSvcLocator): AthAlgorithm(name, pSvcLocator) { }
+
+LVL1::eFEXNtupleWriter::~eFEXNtupleWriter() {
+
+}
+
+StatusCode LVL1::eFEXNtupleWriter::initialize () {
+  ServiceHandle<ITHistSvc> histSvc("THistSvc",name()); 
+  CHECK( histSvc.retrieve() );
+  m_myTree = new TTree("data","data");
+  CHECK( histSvc->regTree("/ANALYSIS/data",m_myTree) );
+  
+  m_load_truth_jet = false;
+
+  m_myTree->Branch ("truth_tauvisible_eta",  &m_truth_tauvisible_eta);
+  m_myTree->Branch ("truth_tauvisible_phi",  &m_truth_tauvisible_phi);
+  m_myTree->Branch ("truth_tauvisible_ET",  &m_truth_tauvisible_ET);
+
+  m_myTree->Branch ("truth_e_eta",  &m_truth_e_eta);
+  m_myTree->Branch ("truth_e_phi",  &m_truth_e_phi);
+  m_myTree->Branch ("truth_e_ET",  &m_truth_e_ET);
+  if (m_load_truth_jet){
+    m_myTree->Branch ("truth_jet_eta",  &m_truth_jet_eta);
+    m_myTree->Branch ("truth_jet_phi",  &m_truth_jet_phi);
+    m_myTree->Branch ("truth_jet_ET",  &m_truth_jet_ET);
+  }
+
+  m_myTree->Branch ("em",  &m_em);
+  m_myTree->Branch ("had",  &m_had);
+
+  m_myTree->Branch ("eg_eta",  &m_eg_eta);
+  m_myTree->Branch ("eg_phi",  &m_eg_phi);
+  m_myTree->Branch ("eg_ET",  &m_eg_ET);
+  m_myTree->Branch ("eg_wstotnum",  &m_eg_WstotNum);
+  m_myTree->Branch ("eg_wstotden",  &m_eg_WstotDen);
+  m_myTree->Branch ("eg_retanum",  &m_eg_RetaNum);
+  m_myTree->Branch ("eg_retaden",  &m_eg_RetaDen);
+  m_myTree->Branch ("eg_rhadnum",  &m_eg_RhadNum);
+  m_myTree->Branch ("eg_rhadden",  &m_eg_RhadDen);
+  m_myTree->Branch ("eg_nTOBs",  &m_eg_nTOBs, "nTOBs");
+  m_myTree->Branch ("eg_haveseed",  &m_eg_haveseed);
+
+  m_myTree->Branch ("tau_Iso",  &m_tau_Iso);
+  m_myTree->Branch ("tau_Et",  &m_tau_Et);
+  m_myTree->Branch ("tau_isCentralTowerSeed",  &m_tau_isCentralTowerSeed);
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::execute () {
+  //ATH_MSG_DEBUG("==== eFEXNtupleWriter ============ execute()");
+  ServiceHandle<StoreGateSvc> evtStore("StoreGateSvc/StoreGateSvc",  "arbitrary");
+  CHECK(evtStore.retrieve() );
+
+  m_eFEXOutputCollection = new eFEXOutputCollection();
+  //m_eFEXOutputCollection = std::make_shared<eFEXOutputCollection>();
+  CHECK(evtStore->retrieve(m_eFEXOutputCollection, "eFEXOutputCollection"));
+
+  CHECK(loadegAlgoVariables());
+  CHECK(loadtauAlgoVariables());
+  CHECK(loadTruthElectron());
+  CHECK(loadTruthTau());
+  if (m_load_truth_jet){
+    CHECK(loadTruthJets());
+  }
+
+  m_myTree->Fill();
+  m_eFEXOutputCollection->clear();
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::finalize () {
+  ATH_MSG_DEBUG("Finalizing " << name() << "...");
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::loadtauAlgoVariables() {
+  m_tau_Iso.clear();
+  m_tau_Et.clear();
+  m_tau_isCentralTowerSeed.clear();
+  for (int i = 0; i < m_eFEXOutputCollection->size(); i++)
+  {
+    m_tau_isCentralTowerSeed.push_back((*(m_eFEXOutputCollection->get_tau(i)))["isCentralTowerSeed"]);
+    m_tau_Et.push_back((*(m_eFEXOutputCollection->get_tau(i)))["Et"]);
+    m_tau_Iso.push_back((*(m_eFEXOutputCollection->get_tau(i)))["Iso"]);
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::loadegAlgoVariables() {
+  m_eg_ET.clear();
+  m_eg_WstotNum.clear();
+  m_eg_WstotDen.clear();
+  m_eg_eta.clear();
+  m_eg_phi.clear();
+  m_eg_haveseed.clear();
+  m_eg_RetaNum.clear();
+  m_eg_RetaDen.clear();
+  m_eg_RhadNum.clear();
+  m_eg_RhadDen.clear();
+
+  m_em.clear();
+  m_had.clear();
+  m_eg_nTOBs = m_eFEXOutputCollection->size();
+  for (int i = 0; i < m_eFEXOutputCollection->size(); i++)
+  {
+    std::map<std::string, float> eFEXegvalue_tem = (*(m_eFEXOutputCollection->get_eg(i)));
+    m_eg_WstotNum.push_back(eFEXegvalue_tem["WstotNum"]);
+    m_eg_WstotDen.push_back(eFEXegvalue_tem["WstotDen"]);
+    m_eg_RetaNum.push_back(eFEXegvalue_tem["RetaNum"]);
+    m_eg_RetaDen.push_back(eFEXegvalue_tem["RetaDen"]);
+    m_eg_RhadNum.push_back(eFEXegvalue_tem["RhadNum"]);
+    m_eg_RhadDen.push_back(eFEXegvalue_tem["RhadDen"]);
+    m_eg_haveseed.push_back(eFEXegvalue_tem["haveseed"]);
+    m_eg_ET.push_back(eFEXegvalue_tem["ET"]);
+    m_eg_eta.push_back(eFEXegvalue_tem["eta"]);
+    m_eg_phi.push_back(eFEXegvalue_tem["phi"]);
+    m_em.push_back(eFEXegvalue_tem["em"]);
+    m_had.push_back(eFEXegvalue_tem["had"]);
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::loadTruthElectron() {
+  m_truth_e_eta.clear();
+  m_truth_e_phi.clear();
+  m_truth_e_ET.clear();
+  const xAOD::TruthEventContainer* truthEvents;
+  CHECK(evtStore()->retrieve( truthEvents, "TruthEvents"));
+  for(auto ite : *truthEvents) {
+    int nParticle = ite->nTruthParticles();
+    for(int i = 0; i < nParticle; i++){
+      const xAOD::TruthParticle* each_particle = ite->truthParticle(i);
+
+      // ignore geant4
+      if(each_particle->barcode() > 200000) continue;
+      // select particles that is not decayed further by the generator
+      if(each_particle->status() != 1) continue;
+      // select electrons
+      if(fabs(each_particle->pdgId()) != 11) continue;
+      // select particles from Z
+      if(!getMother(each_particle, 23)) continue;
+
+      m_truth_e_ET.push_back(each_particle->p4().Pt());
+      m_truth_e_eta.push_back(each_particle->p4().Eta());
+      m_truth_e_phi.push_back(each_particle->p4().Phi());
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::loadTruthJets() {
+  m_truth_jet_eta.clear();
+  m_truth_jet_phi.clear();
+  m_truth_jet_ET.clear();
+  const xAOD::JetContainer* truth_jets;
+  StatusCode sc = evtStore()->retrieve( truth_jets, m_jet_container_name);
+  if (sc ==  StatusCode::FAILURE){
+    m_jet_container_name = "InTimeAntiKt4TruthJets";
+    StatusCode sc2 = evtStore()->retrieve( truth_jets, m_jet_container_name);
+    if (sc2 ==  StatusCode::FAILURE){
+      ATH_MSG_DEBUG("eFEXNtupleWriter::loadTruthJets() Unable to determine truth jet container");
+      m_load_truth_jet = false;
+      return StatusCode::SUCCESS;
+    }
+  }
+  for (unsigned i=0; i!=truth_jets->size(); i++) {
+    const xAOD::Jet* each_jet = (*truth_jets)[i];
+    if(each_jet->pt()<10000) continue;
+    m_truth_jet_eta.push_back(each_jet->p4().Eta());
+    m_truth_jet_phi.push_back(each_jet->p4().Phi());
+    m_truth_jet_ET.push_back(each_jet->p4().Et());
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode LVL1::eFEXNtupleWriter::loadTruthTau() {
+  m_truth_tauvisible_eta.clear();
+  m_truth_tauvisible_phi.clear();
+  m_truth_tauvisible_ET.clear();
+  const xAOD::TruthEventContainer* truthEvents;
+  CHECK( evtStore()->retrieve( truthEvents, "TruthEvents"));
+  for (auto ite : *truthEvents) {
+    int nParticle = ite->nTruthParticles();
+    for(int i = 0; i < nParticle; i++) {
+      const xAOD::TruthParticle* each_particle = ite->truthParticle(i);
+      // ignore geant4
+      if (each_particle->barcode() > 200000) continue;
+      // select final state particles and decaying hadrons, muons or taus
+      if (each_particle->status() != 1 && each_particle->status() != 2) continue;
+      // select tau
+      if (fabs(each_particle->pdgId()) != 15) continue;
+      std::unique_ptr<TLorentzVector> p4_visible = visibleTauP4(each_particle);
+
+      if (!p4_visible) break;
+      m_truth_tauvisible_eta.push_back(p4_visible->Eta());
+      m_truth_tauvisible_phi.push_back(p4_visible->Phi());
+      m_truth_tauvisible_ET.push_back(p4_visible->Et());
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+std::unique_ptr<TLorentzVector> LVL1::eFEXNtupleWriter::visibleTauP4(const xAOD::TruthParticle* particle) {
+  std::unique_ptr<TLorentzVector> psum(new TLorentzVector(0,0,0,0));
+  // ignore documentation particles. Attempt to find the nOutgoingParticles() of a documentation particle 
+  // causes crash.
+  // It still gives the correct result, but I don't know why I have to do this.
+  if (particle->status() == 3) {
+    return psum;
+  }
+  const xAOD::TruthVertex* decay_vertex = particle->decayVtx();
+  decay_vertex->nOutgoingParticles();
+  for(uint i=0; i < decay_vertex->nOutgoingParticles(); i++) {
+    const xAOD::TruthParticle* each_particle = decay_vertex->outgoingParticle(i);
+    int pid = fabs(each_particle->pdgId());
+    // particle that is not decayed further by the generator
+    if (each_particle->status() == 1) {
+      // ignore neutrinos
+      if (pid ==  12 || pid ==  14 || pid ==  16) continue;
+      // ignore leptonic decay events
+      if (pid ==  11 || pid ==  13) return std::unique_ptr<TLorentzVector>(nullptr);
+      (*psum) += each_particle->p4();
+    }
+    else{
+      std::unique_ptr<TLorentzVector> p4_tem = visibleTauP4(each_particle);
+      if (!p4_tem) return std::unique_ptr<TLorentzVector>(nullptr);
+      (*psum) += (*p4_tem);
+    }
+  }
+  return psum;
+}
+
+std::unique_ptr<TLorentzVector> LVL1::eFEXNtupleWriter::invisibleTauP4(const xAOD::TruthParticle* particle) {
+  std::unique_ptr<TLorentzVector> psum(new TLorentzVector(0,0,0,0));
+  // ignore documentation particles. Attempt to find the nOutgoingParticles() of a documentation particle 
+  // causes crash.
+  // It still gives the correct result, but I don't know why I have to do this.
+  if (particle->status() == 3) {
+    return psum;
+  }
+  const xAOD::TruthVertex* decay_vertex = particle->decayVtx();
+  for (uint i=0; i < decay_vertex->nOutgoingParticles(); i++) {
+    const xAOD::TruthParticle* each_particle = decay_vertex->outgoingParticle(i);
+    int pid = fabs(each_particle->pdgId());
+    // particle that is not decayed further by the generator
+    if (each_particle->status() == 1) {
+      // ignore leptonic decay events
+      if (pid ==  11 || pid ==  13) return std::unique_ptr<TLorentzVector>(nullptr);
+      // select neutrinos
+      if (pid ==  12 || pid ==  14 || pid ==  16) (*psum) += each_particle->p4();
+    }
+    else {
+      std::unique_ptr<TLorentzVector> p4_tem = invisibleTauP4(each_particle);
+      if (!p4_tem) return std::unique_ptr<TLorentzVector>(nullptr);
+      (*psum) += (*p4_tem);
+    }
+  }
+  return psum;
+}
+
+const xAOD::TruthParticle* LVL1::eFEXNtupleWriter::getMother(const xAOD::TruthParticle* particle, int motherPid) {
+   const xAOD::TruthVertex* productionVector = particle->prodVtx();
+   if (!productionVector) return NULL;
+   for (long unsigned int i = 0; i < productionVector->nIncomingParticles(); i++) {
+      const xAOD::TruthParticle* mother = productionVector->incomingParticle(i);
+      if (mother->pdgId()==motherPid) return mother;
+      const xAOD::TruthParticle* grandmother = getMother(mother, motherPid);
+      if (grandmother) return grandmother;
+   }
+   return NULL;
+}
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXOutputCollection.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXOutputCollection.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..21de240f8cf1c99073447e280bd08c295b671917
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXOutputCollection.cxx
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXOutputCollection.cxx  -  
+//                              -------------------
+//     begin                : 28 02 2020
+//     email                : tong.qiu@cern.ch
+//  **************************************************************************
+
+#include "L1CaloFEXSim/eFEXOutputCollection.h"
+
+LVL1::eFEXOutputCollection::~eFEXOutputCollection()
+{
+  for (auto iValues : m_allvalues_eg) {
+    delete iValues;
+  }
+  for (auto iValues : m_allvalues_tau) {
+    delete iValues;
+  }
+}
+
+void LVL1::eFEXOutputCollection::clear()
+{
+  for (auto iValues : m_allvalues_eg) {
+    iValues->clear();
+  }
+  for (auto iValues : m_allvalues_tau) {
+    iValues->clear();
+  }
+}
+
+void LVL1::eFEXOutputCollection::addValue_eg(std::string key, float value)
+{
+  m_values_tem_eg.insert(std::make_pair(key, value));
+}
+
+void LVL1::eFEXOutputCollection::addValue_tau(std::string key, float value)
+{
+  m_values_tem_tau.insert(std::make_pair(key, value));
+}
+
+void LVL1::eFEXOutputCollection::fill_eg()
+{
+  std::map<std::string, float>* values_local = new std::map<std::string, float>(m_values_tem_eg);
+  m_allvalues_eg.push_back(values_local);
+  m_values_tem_eg.clear();
+}
+
+void LVL1::eFEXOutputCollection::fill_tau()
+{
+  std::map<std::string, float>* values_local = new std::map<std::string, float>(m_values_tem_tau);
+  m_allvalues_tau.push_back(values_local);
+  m_values_tem_tau.clear();
+}
+
+int LVL1::eFEXOutputCollection::size()
+{
+  return m_allvalues_eg.size();
+}
+
+std::map<std::string, float>* LVL1::eFEXOutputCollection::get_eg(int location)
+{
+  return m_allvalues_eg[location];
+}
+
+std::map<std::string, float>* LVL1::eFEXOutputCollection::get_tau(int location)
+{
+  return m_allvalues_tau[location];
+}
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXSim.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXSim.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0863dd16d569f6f78c19df343fb1b4ed164a8952
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXSim.cxx
@@ -0,0 +1,190 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXSim  -  description
+//                              -------------------
+//     begin                : 12 07 2019
+//     email                : jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#include "L1CaloFEXSim/eFEXSim.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eFEXFPGA.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+namespace LVL1 {
+
+  eFEXSim::eFEXSim(const std::string& type,const std::string& name,const IInterface* parent):
+    AthAlgTool(type,name,parent)
+  {
+    declareInterface<IeFEXSim>(this);
+  }
+
+
+  //================ Initialisation =================================================
+
+  StatusCode eFEXSim::initialize()
+  {
+    return StatusCode::SUCCESS;
+  }
+
+  //================ Finalisation =================================================
+
+  StatusCode eFEXSim::finalize()
+  {
+    return StatusCode::SUCCESS;
+  }
+
+
+  void eFEXSim::reset()
+  {
+
+    m_id = -1;
+    m_eFEXFPGACollection.clear();
+    for (int i=0; i<10; i++){
+      for (int j=0; j<18; j++){
+	  m_eTowersIDs[i][j] = 0;
+	}
+    }
+    
+  }
+
+  void eFEXSim::init(int id)
+  {
+    m_id = id;
+  }
+
+  /** Destructor */
+  eFEXSim::~eFEXSim()
+  {
+  }
+  
+ void eFEXSim::execute(){
+
+ }
+
+StatusCode eFEXSim::NewExecute(int tmp_eTowersIDs_subset[10][18]){
+  
+  std::copy(&tmp_eTowersIDs_subset[0][0], &tmp_eTowersIDs_subset[0][0]+(10*18),&m_eTowersIDs[0][0]);
+
+  int tmp_eTowersIDs_subset_FPGA[10][6];
+
+  ATH_CHECK( m_eFEXFPGATool.retrieve() );
+  
+  //FPGA 0----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 0; mycol<6; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  ATH_CHECK(m_eFEXFPGATool->init(0, m_id));
+  m_eFEXFPGATool->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  ATH_CHECK(m_eFEXFPGATool->execute());
+  m_eFEXFPGATool->reset();
+  //FPGA 0----------------------------------------------------------------------------------------------------------------------------------------------
+  
+  //FPGA 1----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 4; mycol<10; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol-4] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  ATH_CHECK(m_eFEXFPGATool->init(1, m_id));
+  m_eFEXFPGATool->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  ATH_CHECK(m_eFEXFPGATool->execute());
+  m_eFEXFPGATool->reset();
+  //FPGA 1----------------------------------------------------------------------------------------------------------------------------------------------
+
+
+  //FPGA 2----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 8; mycol<14; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol-8] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  ATH_CHECK(m_eFEXFPGATool->init(2, m_id));
+  m_eFEXFPGATool->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  ATH_CHECK(m_eFEXFPGATool->execute());
+  m_eFEXFPGATool->reset();
+  //FPGA 2----------------------------------------------------------------------------------------------------------------------------------------------
+
+  //FPGA 3----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 12; mycol<18; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol-12] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  ATH_CHECK(m_eFEXFPGATool->init(0, m_id));
+  m_eFEXFPGATool->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  ATH_CHECK(m_eFEXFPGATool->execute());
+  m_eFEXFPGATool->reset();
+  //FPGA 3----------------------------------------------------------------------------------------------------------------------------------------------
+
+  return StatusCode::SUCCESS;
+
+}
+
+void eFEXSim::SetTowersAndCells_SG(int tmp_eTowersIDs_subset[10][18]){ // METHOD USING ONLY IDS
+
+  std::copy(&tmp_eTowersIDs_subset[0][0], &tmp_eTowersIDs_subset[0][0]+(10*18),&m_eTowersIDs[0][0]);
+  
+  int tmp_eTowersIDs_subset_FPGA[10][6];
+  
+  //FPGA 0----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 0; mycol<6; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }  
+  m_eFEXFPGACollection.at(0)->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  //FPGA 0----------------------------------------------------------------------------------------------------------------------------------------------
+
+  //FPGA 1----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 4; mycol<10; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol-4] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  m_eFEXFPGACollection.at(1)->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  //FPGA 1----------------------------------------------------------------------------------------------------------------------------------------------
+  
+
+  //FPGA 2----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 8; mycol<14; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol-8] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  m_eFEXFPGACollection.at(2)->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  //FPGA 2----------------------------------------------------------------------------------------------------------------------------------------------
+  
+  //FPGA 3----------------------------------------------------------------------------------------------------------------------------------------------
+  memset(tmp_eTowersIDs_subset_FPGA, 0, sizeof tmp_eTowersIDs_subset_FPGA);
+  for (int myrow = 0; myrow<10; myrow++){
+    for (int mycol = 12; mycol<18; mycol++){
+      tmp_eTowersIDs_subset_FPGA[myrow][mycol-12] = tmp_eTowersIDs_subset[myrow][mycol];
+    }
+  }
+  m_eFEXFPGACollection.at(3)->SetTowersAndCells_SG(tmp_eTowersIDs_subset_FPGA);
+  //FPGA 3----------------------------------------------------------------------------------------------------------------------------------------------
+  
+}
+  
+
+} // end of namespace bracket
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXSysSim.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXSysSim.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cb47ef03620e4e4e15cde7ec218fa3979fc2e854
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXSysSim.cxx
@@ -0,0 +1,380 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXSysSim  -  description
+//                              -------------------
+//     begin                : 12 07 2019
+//     email                : jacob.julian.kempster@cern.ch alison.elliot@cern.ch
+//  ***************************************************************************/
+
+#include "L1CaloFEXSim/eFEXSysSim.h"
+#include "L1CaloFEXSim/eFEXSim.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+#include "StoreGate/WriteHandle.h"
+#include "StoreGate/ReadHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+
+#include <ctime>
+
+namespace LVL1 {
+  
+  
+  // default constructor for persistency
+
+  eFEXSysSim::eFEXSysSim(const std::string& type,const std::string& name,const IInterface* parent):
+    AthAlgTool(type,name,parent)
+  {
+    declareInterface<IeFEXSysSim>(this);
+
+  }
+
+    
+  /** Destructor */
+  //eFEXSysSim::~eFEXSysSim()
+  //{
+  //}
+
+  //================ Initialisation =================================================
+
+  StatusCode eFEXSysSim::initialize()
+  {
+    
+    ATH_CHECK(m_eTowerContainerSGKey.initialize());
+
+    ATH_CHECK( m_eFEXSimTool.retrieve() );
+
+    return StatusCode::SUCCESS;
+  }
+
+  //================ Finalisation =================================================
+
+  StatusCode eFEXSysSim::finalize()
+  {
+    return StatusCode::SUCCESS;
+  }
+
+  
+  void eFEXSysSim::init()  {
+
+  }
+
+  void eFEXSysSim::cleanup()  {
+
+    m_eFEXCollection.clear();
+    m_eTowersColl.clear();
+
+  }
+
+
+  int eFEXSysSim::calcTowerID(int eta, int phi, int mod)  {
+
+    return ((64*eta) + phi + mod);
+
+  }
+
+  StatusCode eFEXSysSim::execute()  {    
+
+    SG::ReadHandle<LVL1::eTowerContainer> this_eTowerContainer(m_eTowerContainerSGKey/*,ctx*/);
+    if(!this_eTowerContainer.isValid()){
+      ATH_MSG_FATAL("Could not retrieve eTowerContainer " << m_eTowerContainerSGKey.key());
+      return StatusCode::FAILURE;
+    }
+
+    // We need to split the towers into 3 blocks in eta and 8 blocks in phi.
+
+    // boundaries in eta: -2.5, -0.8, 0.8, 2.5
+    // REAL boundaries in eta (overlaps must occur for sliding window algorithms!): -2.5, -0.7, -0.9, 0.9, 0.7, 2.5
+    // Written explicitly:
+    // -2.5 -> -0.7
+    // -0.9 -> 0.9
+    // 0.7 -> 2.5
+
+    // boundaries in phi: 0.2, 1.0, 1.8, 2.6, 3.4, 4.2, 5.0, 5.8
+    // Written explicityl with REAL boundaries in eta (overlaps must occur for sliding window algorithms!)
+    // 0.1 -> 1.1
+    // 0.9 -> 1.9
+    // 1.7 -> 2.7
+    // 2.5 -> 3.5
+    // 3.3 -> 4.3
+    // 4.1 -> 5.1
+    // 4.9 -> 5.9
+    // 5.7 -> 0.3
+
+    // C-SIDE NEGATIVE EFEXs
+    // DO THE LEFT-MOST (NEGATIVE ETA) EFEXs FIRST
+    int fexcounter = 0;
+    // Example values for eFEX 0
+    //id_modifier + phi + (64 * eta)
+    int emecEta = 24; int emecPhi = 1; int emecMod = 500000;
+    int initialEMEC = calcTowerID(emecEta,emecPhi,emecMod); //501537;
+    int transEta = 14; int transPhi = 1; int transMod = 300000;
+    int initialTRANS = calcTowerID(transEta,transPhi,transMod); //300897;
+    int embEta = 13; int embPhi = 1; int embMod = 100000;
+    int initialEMB = calcTowerID(embEta,embPhi,embMod); //100833;
+
+    for (int thisEFEX=0; thisEFEX<=21; thisEFEX+=3){
+      
+      if(fexcounter > 0){ initialEMEC += 8; initialTRANS += 8; initialEMB += 8; } // TODO // SOMEHOW REMOVE HARD-CODING?
+
+      // decide which subset of towers (and therefore supercells) should go to the eFEX
+      std::map<int,eTower> tmp_eTowersColl_subset;
+      
+      // let's try doing this with an array initially just containing tower IDs.
+      int tmp_eTowersIDs_subset [10][18];
+      
+      int rows = sizeof tmp_eTowersIDs_subset / sizeof tmp_eTowersIDs_subset[0];
+      int cols = sizeof tmp_eTowersIDs_subset[0] / sizeof tmp_eTowersIDs_subset[0][0];
+
+      // set the EMEC part
+      for(int thisCol=0; thisCol<10; thisCol++){
+	for(int thisRow=0; thisRow<rows; thisRow++){
+
+	  int towerid = initialEMEC - (thisCol * 64) + thisRow;
+
+	  if( (thisEFEX == 21) && (thisRow >= 7)){ towerid -= 64; };
+	  
+	  tmp_eTowersIDs_subset[thisRow][thisCol] = towerid;
+	  tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	  std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+	}
+      }
+
+      // set the TRANS part
+      for(int thisRow = 0; thisRow < rows; thisRow++){
+
+	int towerid = initialTRANS + thisRow;
+
+	if( (thisEFEX == 21) && (thisRow >= 7)){ towerid -= 64; };
+
+	tmp_eTowersIDs_subset[thisRow][10] = towerid;
+	tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+      }
+
+      // set the EMB part
+      for(int thisCol = 11; thisCol < cols; thisCol++){
+	for(int thisRow=0; thisRow<rows; thisRow++){
+
+	  int towerid = initialEMB - ( (thisCol-11) * 64) + thisRow;
+
+	  if( (thisEFEX == 21) && (thisRow >= 7)){ towerid -= 64; };
+
+	  tmp_eTowersIDs_subset[thisRow][thisCol] = towerid;
+	  tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	  std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+	}
+      }
+      
+
+      if(false){
+	ATH_MSG_DEBUG("CONTENTS OF eFEX " << thisEFEX << " :");
+        for (int thisRow=rows-1; thisRow>=0; thisRow--){
+          for (int thisCol=0; thisCol<cols; thisCol++){
+            int tmptowerid = tmp_eTowersIDs_subset[thisRow][thisCol];
+            const float tmptowereta = this_eTowerContainer->findTower(tmptowerid)->eta();
+            const float tmptowerphi = this_eTowerContainer->findTower(tmptowerid)->phi();
+            if(thisCol != cols-1){ ATH_MSG_DEBUG("|  " << tmptowerid << "([" << tmptowerphi << "][" << tmptowereta << "])  "); }
+            else { ATH_MSG_DEBUG("|  " << tmptowerid << "([" << tmptowereta << "][" << tmptowerphi << "])  |"); }
+          }
+        }
+      }
+
+
+      m_eFEXSimTool->init(thisEFEX);
+      ATH_CHECK(m_eFEXSimTool->NewExecute(tmp_eTowersIDs_subset));
+      m_eFEXSimTool->reset();
+
+      fexcounter++;
+
+    }
+
+    // CENTRAL EFEXs
+    // DO THE CENTRAL EFEXs SECOND
+    fexcounter = 0;
+    int embnegEta = 8; int embnegPhi = 1; int embnegMod = 100000;
+    int initialEMB_neg = calcTowerID(embnegEta,embnegPhi,embnegMod); //100513;
+    int embposEta = 0; int embposPhi = 1; int embposMod = 200000;
+    int initialEMB_pos = calcTowerID(embposEta,embposPhi,embposMod); //200001;
+
+    for (int thisEFEX=1; thisEFEX<=22; thisEFEX+=3){
+
+      if(fexcounter > 0){  initialEMB_neg += 8; initialEMB_pos += 8; }
+      
+      // decide which subset of towers (and therefore supercells) should go to the eFEX
+      std::map<int,eTower> tmp_eTowersColl_subset;
+      
+      // doing this with an array initially just containing tower IDs.
+      int tmp_eTowersIDs_subset [10][18];
+
+      int rows = sizeof tmp_eTowersIDs_subset / sizeof tmp_eTowersIDs_subset[0];
+      int cols = sizeof tmp_eTowersIDs_subset[0] / sizeof tmp_eTowersIDs_subset[0][0];
+
+      // set the EMB part
+      for(int thisCol = 0; thisCol < cols; thisCol++){
+        for(int thisRow=0; thisRow<rows; thisRow++){
+	  int towerid = -1;
+
+	  int tmp_initEMB = initialEMB_neg;
+
+	  if(thisCol < 9){
+	    towerid = tmp_initEMB - ( (thisCol) * 64) + thisRow;
+	  }
+	  else{
+	    tmp_initEMB = initialEMB_pos;
+	    towerid = tmp_initEMB + ( (thisCol-9) * 64) + thisRow;
+	  }
+
+	  if( (thisEFEX == 22) && (thisRow >= 7)){ towerid -= 64; };
+
+          tmp_eTowersIDs_subset[thisRow][thisCol] = towerid;
+
+          tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	  std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+        }
+      }
+      
+
+      if(false){
+	ATH_MSG_DEBUG("CONTENTS OF eFEX " << thisEFEX << " :");
+        for (int thisRow=rows-1; thisRow>=0; thisRow--){
+          for (int thisCol=0; thisCol<cols; thisCol++){
+            int tmptowerid = tmp_eTowersIDs_subset[thisRow][thisCol];
+            const float tmptowereta = this_eTowerContainer->findTower(tmptowerid)->eta();
+            const float tmptowerphi = this_eTowerContainer->findTower(tmptowerid)->phi();
+            if(thisCol != cols-1){ ATH_MSG_DEBUG("|  " << tmptowerid << "([" << tmptowereta << "][" << tmptowerphi << "])  "); }
+            else { ATH_MSG_DEBUG("|  " << tmptowerid << "([" << tmptowereta << "][" << tmptowerphi << "])  |"); }
+          }
+        }
+      }
+
+      //tool use instead
+      m_eFEXSimTool->init(thisEFEX);
+      ATH_CHECK(m_eFEXSimTool->NewExecute(tmp_eTowersIDs_subset));
+      m_eFEXSimTool->reset();
+
+      fexcounter++;
+
+    }
+
+    // POSITIVE EFEXs
+    // LET'S DO THE RIGHT-MOST (POSTITIVE ETA) EFEXs THIRD
+    fexcounter = 0;
+    // Example values for eFEX 0
+    emecEta = 15; emecPhi = 1; emecMod = 600000;
+    initialEMEC = calcTowerID(emecEta,emecPhi,emecMod); //600961;
+    transEta = 14; transPhi = 1; transMod = 400000;
+    initialTRANS = calcTowerID(transEta,transPhi,transMod); //400897;
+    embEta = 7; embPhi = 1; embMod = 200000;
+    initialEMB = calcTowerID(embEta,embPhi,embMod); //200449;
+
+    for (int thisEFEX=2; thisEFEX<=23; thisEFEX+=3){
+
+      if(fexcounter > 0){ initialEMEC += 8; initialTRANS += 8; initialEMB += 8; }
+
+      // decide which subset of towers (and therefore supercells) should go to the eFEX
+      std::map<int,eTower> tmp_eTowersColl_subset;
+
+      // doing this with an array initially just containing tower IDs.
+      int tmp_eTowersIDs_subset [10][18];
+
+      int rows = sizeof tmp_eTowersIDs_subset / sizeof tmp_eTowersIDs_subset[0];
+      int cols = sizeof tmp_eTowersIDs_subset[0] / sizeof tmp_eTowersIDs_subset[0][0];
+
+      // set the EMB part
+      for(int thisCol = 0; thisCol < 7; thisCol++){
+        for(int thisRow=0; thisRow<rows; thisRow++){
+          int towerid = initialEMB + ( (thisCol) * 64) + thisRow;
+
+          if( (thisEFEX == 23) && (thisRow >= 7)){ towerid -= 64; };
+
+          tmp_eTowersIDs_subset[thisRow][thisCol] = towerid;
+          tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	  std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+        }
+      }
+      // set the TRANS part
+      for(int thisRow = 0; thisRow < rows; thisRow++){
+        int towerid = initialTRANS + thisRow;
+
+        if( (thisEFEX == 23) && (thisRow >= 7)){ towerid -= 64; };
+
+        tmp_eTowersIDs_subset[thisRow][7] = towerid;
+        tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+      }
+      // set the EMEC part
+      for(int thisCol=8; thisCol<cols; thisCol++){
+        for(int thisRow=0; thisRow<rows; thisRow++){
+          int towerid = initialEMEC + ( (thisCol-8) * 64) + thisRow;
+
+          if( (thisEFEX == 23) && (thisRow >= 7)){ towerid -= 64; };
+
+          tmp_eTowersIDs_subset[thisRow][thisCol] = towerid;
+          tmp_eTowersColl_subset.insert( std::map<int, eTower>::value_type(towerid,  *(this_eTowerContainer->findTower(towerid))));
+
+	  std::vector<Identifier> supercellIDs = this_eTowerContainer->findTower(towerid)->getSCIDs();
+
+        }
+      }
+
+
+      if(false){
+	ATH_MSG_DEBUG("CONTENTS OF eFEX " << thisEFEX << " :");
+	for (int thisRow=rows-1; thisRow>=0; thisRow--){
+	  for (int thisCol=0; thisCol<cols; thisCol++){
+	    int tmptowerid = tmp_eTowersIDs_subset[thisRow][thisCol];
+	    const float tmptowereta = this_eTowerContainer->findTower(tmptowerid)->eta();
+	    const float tmptowerphi = this_eTowerContainer->findTower(tmptowerid)->phi();
+	    if(thisCol != cols-1){ ATH_MSG_DEBUG("|  " << tmptowerid << "([" << tmptowereta << "][" << tmptowerphi << "])  "); }
+	    else { ATH_MSG_DEBUG("|  " << tmptowerid << "([" << tmptowereta << "][" << tmptowerphi << "])  |"); }
+	  }
+	}
+      }
+
+      //tool use instead
+      m_eFEXSimTool->init(thisEFEX);
+      ATH_CHECK(m_eFEXSimTool->NewExecute(tmp_eTowersIDs_subset));
+      m_eFEXSimTool->reset();
+
+      fexcounter++;
+
+    }
+    
+    //Collate TOBS returned from eFEXSims. Should that be here?
+    // ToDo
+    // To implement
+    // {--Implement--}
+
+
+    //Send TOBs to bytestream?
+    // ToDo
+    // To implement
+    // {--Implement--}
+
+    return StatusCode::SUCCESS;
+
+  }
+
+  
+} // end of namespace bracket
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXegAlgo.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXegAlgo.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a99a3773f035631f7981d692eb992134a186e415
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXegAlgo.cxx
@@ -0,0 +1,338 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXegAlgo  -  description
+//                              -------------------
+//     begin                : 24 02 2020
+//     email                : antonio.jacques.costa@cern.ch ulla.blumenschein@cern.ch tong.qiu@cern.ch
+//  ***************************************************************************/
+#include <iostream>
+#include <vector>
+
+#include "L1CaloFEXSim/eFEXegAlgo.h"
+#include "L1CaloFEXSim/eFEXegTOB.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "StoreGate/StoreGateSvc.h"
+
+namespace LVL1 {
+
+  // default constructor for persistency
+eFEXegAlgo::eFEXegAlgo(const std::string& type, const std::string& name, const IInterface* parent):
+    AthAlgTool(type, name, parent) 
+  {
+    declareInterface<IeFEXegAlgo>(this);
+  }
+
+  /** Destructor */
+eFEXegAlgo::~eFEXegAlgo()
+{
+}
+
+StatusCode eFEXegAlgo::initialize(){
+
+  ATH_CHECK(m_eFEXegAlgo_eTowerContainerKey.initialize());
+
+  return StatusCode::SUCCESS;
+
+}
+
+
+StatusCode eFEXegAlgo::safetyTest(){
+
+  // This is to test that it will also work in the other functions, as we call this object from SG in every function but don't want them all to have to return StatusCodes, and i'm not sure how to make this a private member instead
+  //ATH_CHECK(m_eFEXegAlgo_eTowerContainerKey.initialize());
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+  if(!jk_eFEXegAlgo_eTowerContainer.isValid()){
+    ATH_MSG_FATAL("Could not retrieve jk_eFEXegAlgo_eTowerContainer " << m_eFEXegAlgo_eTowerContainerKey.key() );
+    return StatusCode::FAILURE;
+  }
+  
+  return StatusCode::SUCCESS;
+
+}
+
+void eFEXegAlgo::setup(int inputTable[3][3]) {
+  
+  std::copy(&inputTable[0][0], &inputTable[0][0] + 9, &m_eFEXegAlgoTowerID[0][0]);
+  
+  setSeed();
+
+}
+
+void LVL1::eFEXegAlgo::getCoreEMTowerET(unsigned int & et) { 
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+  
+  const LVL1::eTower * tmpTower = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[1][1]);
+  et = tmpTower->getLayerTotalET(0) + tmpTower->getLayerTotalET(1) + tmpTower->getLayerTotalET(2) + tmpTower->getLayerTotalET(3);
+
+}
+
+void LVL1::eFEXegAlgo::getCoreHADTowerET(unsigned int & et) { 
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+
+  const LVL1::eTower * tmpTower = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[1][1]);
+  et = tmpTower->getLayerTotalET(4);
+
+}
+
+void LVL1::eFEXegAlgo::getRealPhi(float & phi) {
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+  phi = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[1][1])->phi();
+  
+}
+
+void LVL1::eFEXegAlgo::getRealEta(float & eta) {
+  
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+
+  eta = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[1][1])->eta() * jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[1][1])->getPosNeg();
+
+}
+
+std::vector<unsigned int> eFEXegAlgo::getReta() {
+
+  std::vector<unsigned int> retavec;
+  unsigned int coresum  = 0;   // 3x2 L2 sum : core
+  unsigned int totalsum = 0;   // 7x3 L2 sum : total
+  unsigned int envsum   = 0;   // total - core : env
+
+  // window limits
+  int iTotalStart = m_seedID-3;
+  int iTotalEnd   = m_seedID+3;
+  int iCoreStart  = m_seedID-1;
+  int iCoreEnd    = m_seedID+1;
+  int phiStart    = -999; 
+  int phiEnd      = -99;
+  if (m_seed_UnD) {
+    phiStart = 0;
+    phiEnd = 1;
+  } else {
+    phiStart = 1;
+    phiEnd = 2;
+  }
+
+  // 3x2 and 7x3 L2 sum
+  for (int i=iTotalStart; i<=iTotalEnd; ++i) { // eta
+    for(int j=0; j<=2; ++j) { // phi
+      if (i>=iCoreStart && i <= iCoreEnd && j>=phiStart && j<=phiEnd) {
+	unsigned int tmp_et; getWindowET(2,j,i,tmp_et);
+	coresum += tmp_et;
+      }
+
+      unsigned int tmptot_et; getWindowET(2,j,i,tmptot_et);
+      totalsum += tmptot_et;
+    }
+  }
+
+  // get environment
+  envsum = totalsum - coresum;
+
+  retavec.push_back(coresum);
+  retavec.push_back(envsum);
+
+  return retavec;
+}
+
+void eFEXegAlgo::getRhad(std::vector<unsigned int> & rhadvec) {
+
+  //std::vector<unsigned int> rhadvec;
+  unsigned int hadsum = 0; // 3x3 Towers Had 
+  unsigned int emsum = 0;  // (1x3 + 3x3 + 3x3 + 1x3) SCs EM
+  
+  int iCoreStart  = m_seedID-1;
+  int iCoreEnd    = m_seedID+1;
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+  
+  // 3x3 Towers Had ; 1x3 L0 + 1x3 L3 EM
+  for (int i=0; i<3; ++i) { // eta
+    for (int j=0; j<=2; ++j) { // phi
+      const eTower * tTower = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[i][j]);
+      hadsum += tTower->getLayerTotalET(4);
+      if (i==1) {
+	emsum += ( tTower->getLayerTotalET(0) + tTower->getLayerTotalET(3) );
+      }
+    }
+  }
+  
+  // 3x3 SCs L1 and L2 sum
+  for (int i=iCoreStart; i<=iCoreEnd; ++i) { // eta
+    for(int j=0; j<=2; ++j) { // phi
+      unsigned int tmp_et_a, tmp_et_b;
+      getWindowET(1,j,i,tmp_et_a);
+      getWindowET(2,j,i,tmp_et_b);
+      emsum += ( tmp_et_a + tmp_et_b );
+    }
+  }   
+  
+  rhadvec.push_back(emsum);
+  rhadvec.push_back(hadsum);
+
+}
+
+void LVL1::eFEXegAlgo::getWstot(std::vector<unsigned int> & output){
+  unsigned int numer = 0;
+  unsigned int den = 0;
+  int iStart = m_seedID - 2;
+  int iEnd = m_seedID + 2;
+
+  for (int i = iStart; i <= iEnd; ++i) { // eta
+    int diff = i - m_seedID;
+    unsigned int weight = diff*diff;
+    for (int j = 0; j <= 2; ++j) { // phi
+      unsigned int eT; getWindowET(1, j, i, eT);
+      numer += eT*weight;
+      den += eT;
+    }
+  }
+  output.push_back(numer);
+  output.push_back(den);
+
+}
+
+unsigned int LVL1::eFEXegAlgo::getET() {
+  int phiUpDownID = 1 + m_seed_UnD - !m_seed_UnD;
+  
+  unsigned int PS_ET_1, PS_ET_2;
+  getWindowET(0, 1, 0, PS_ET_1);
+  getWindowET(0, phiUpDownID, 0, PS_ET_2);
+  unsigned int L1_ET_1, L1_ET_2, L1_ET_3, L1_ET_4, L1_ET_5, L1_ET_6;
+  getWindowET(1, 1, m_seedID, L1_ET_1); getWindowET(1, 1, m_seedID - 1, L1_ET_2); getWindowET(1, 1, m_seedID + 1, L1_ET_3);
+  getWindowET(1, phiUpDownID, m_seedID, L1_ET_4); getWindowET(1, phiUpDownID, m_seedID - 1, L1_ET_5); getWindowET(1, phiUpDownID, m_seedID + 1, L1_ET_6);
+  unsigned int L2_ET_1, L2_ET_2, L2_ET_3, L2_ET_4, L2_ET_5, L2_ET_6;
+  getWindowET(2, 1, m_seedID, L2_ET_1); getWindowET(2, 1, m_seedID - 1, L2_ET_2); getWindowET(2, 1, m_seedID + 1, L2_ET_3);
+  getWindowET(2, phiUpDownID, m_seedID, L2_ET_4); getWindowET(2, phiUpDownID, m_seedID - 1, L2_ET_5); getWindowET(2, phiUpDownID, m_seedID + 1, L2_ET_6);
+  unsigned int L3_ET_1, L3_ET_2;
+  getWindowET(3, 1, 0, L3_ET_1); getWindowET(3, phiUpDownID, 0, L3_ET_2);
+
+  unsigned int totET = PS_ET_1 + PS_ET_2;
+  totET += L1_ET_1 + L1_ET_2 + L1_ET_3 + L1_ET_4 + L1_ET_5 + L1_ET_6;
+  totET += L2_ET_1 + L2_ET_2 + L2_ET_3 + L2_ET_4 + L2_ET_5 + L2_ET_6;
+  totET += L3_ET_1 + L3_ET_2;
+
+  return totET;
+
+}
+
+std::unique_ptr<eFEXegTOB> LVL1::eFEXegAlgo::geteFEXegTOB() {
+  std::unique_ptr<eFEXegTOB> out = std::make_unique<eFEXegTOB>();
+;// = new eFEXegTOB();
+  out->setET(getET());
+
+  std::vector<unsigned int> temvector;
+  getWstot(temvector);
+
+  out->setWstotNum(temvector[0]);
+  out->setWstotDen(temvector[1]);
+  getRhad(temvector);
+  out->setRhadNum(temvector[1]);
+  out->setRhadDen(temvector[0] + temvector[1]);
+  temvector = getReta();
+  out->setRetaNum(temvector[0]);
+  out->setRetaDen(temvector[0] + temvector[1]);
+  out->setSeedUnD(m_seed_UnD);
+  out->setSeed(m_seedID);
+  return out;
+}
+
+void LVL1::eFEXegAlgo::getWindowET(int layer, int jPhi, int SCID, unsigned int & outET) {
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXegAlgo_eTowerContainer(m_eFEXegAlgo_eTowerContainerKey/*,ctx*/);
+
+  if (SCID<0) { // left towers in eta
+    int etaID = 4+SCID;
+    const eTower * tmpTower = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[jPhi][0]);
+    if (layer==1 || layer==2) {
+      outET = tmpTower->getET(layer,etaID);
+    } else if (layer==0 || layer==3 || layer==4) {
+      outET = tmpTower->getLayerTotalET(layer);
+    }
+  } else if (SCID>=0 && SCID<4) { // central towers in eta
+    const eTower * tmpTower = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[jPhi][1]);
+    if (layer==1 || layer==2) { 
+      outET = tmpTower->getET(layer,SCID);
+    } else if (layer==0 || layer==3 || layer==4) {
+      outET = tmpTower->getLayerTotalET(layer);
+    }
+  } else if (SCID>=4){ // right towers in eta
+    int etaID = SCID-4;
+    const eTower * tmpTower = jk_eFEXegAlgo_eTowerContainer->findTower(m_eFEXegAlgoTowerID[jPhi][2]);
+    if (layer==1 || layer==2) {  
+      outET = tmpTower->getET(layer,etaID);
+    } else if (layer==0 || layer==3 || layer==4) {
+      outET = tmpTower->getLayerTotalET(layer);
+    }
+  }
+
+}
+  
+  
+void eFEXegAlgo::setSeed() {
+
+  m_haveseed = false;
+  unsigned int tmpID = 999;
+  unsigned int maxET = 0;
+  
+  for (int i=0; i<4 ; ++i) {
+    int iSeedL = i-1;
+    int iSeedR = i+1;
+
+    // eta ID of candidate seed
+    unsigned int cETUp;
+    getWindowET(2,0,i,cETUp);
+    unsigned int iSeedET;
+    getWindowET(2,1,i, iSeedET);
+    unsigned int cETDown;
+    getWindowET(2,2,i, cETDown);
+    
+    // left of candidate seed
+    unsigned int lETUp;
+    getWindowET(2,0,iSeedL,lETUp);
+    unsigned int lET;
+    getWindowET(2,1,iSeedL,lET);
+    unsigned int lETDown;
+    getWindowET(2,2,iSeedL,lETDown);
+    
+    // right of candidate seed
+    unsigned int rETUp;
+    getWindowET(2,0,iSeedR,rETUp);
+    unsigned int rET;
+    getWindowET(2,1,iSeedR,rET);
+    unsigned int rETDown;
+    getWindowET(2,2,iSeedR,rETDown);
+    
+    // greater for left and up cells, greater or equal for right and down ones
+    if (iSeedET>lET && iSeedET>=rET 
+        && iSeedET>lETUp    && iSeedET>cETUp    && iSeedET>rETUp 
+        && iSeedET>=lETDown && iSeedET>=cETDown && iSeedET>=rETDown) {
+      if (iSeedET>maxET) { // if two maxima exist, keep the one to the left
+        maxET = iSeedET;
+        tmpID = i;
+      }
+    }
+  }
+  
+  if(tmpID!=999) {
+    m_seedID = tmpID;
+    m_haveseed = true;
+    unsigned int tmp_et_1, tmp_et_2;
+    getWindowET(2,0,m_seedID,tmp_et_1);
+    getWindowET(2,2,m_seedID,tmp_et_2);
+    if (tmp_et_1 >= tmp_et_2) {
+      m_seed_UnD = true; // go up if energy greater or equal to bottom
+    } 
+  }
+}
+
+} // namespace LVL1
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXegTOB.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXegTOB.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b3780a91ee9cbb6bc0d5b4fdf1c354b4dcd1ad07
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXegTOB.cxx
@@ -0,0 +1,95 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXegTOB.cxx  -  
+//                              -------------------
+//     begin                : 17 01 2020
+//     email                : tong.qiu@cern.ch
+//  **************************************************************************
+
+
+#include "L1CaloFEXSim/eFEXegTOB.h"
+
+
+LVL1::eFEXegTOB::eFEXegTOB():
+  m_eta{99999},
+  m_phi{99999},
+  m_ET{99999},
+  m_Reta_Num{99999},
+  m_Reta_Den{99999},
+  m_Rhad_Num{99999},
+  m_Rhad_Den{99999},
+  m_Wstot_Num{99999},
+  m_Wstot_Den{99999},
+  m_FPGA_ID{99999},
+  m_eFEX_ID{99999},
+  m_seed_UnD{1},
+  m_seed{99999}
+{}
+
+unsigned int LVL1::eFEXegTOB::setEta(unsigned int eta) {
+  m_eta = eta;
+  return m_eta;
+}
+
+unsigned int LVL1::eFEXegTOB::setPhi(unsigned int phi) {
+  m_phi = phi;
+  return m_phi;
+}
+
+unsigned int LVL1::eFEXegTOB::setET(unsigned int et) {
+  m_ET = et;
+  return m_ET;
+}
+
+unsigned int LVL1::eFEXegTOB::setFPGAID(unsigned int fpgaid) {
+  m_FPGA_ID = fpgaid;
+  return m_FPGA_ID; 
+}
+
+unsigned int LVL1::eFEXegTOB::seteFEXID(unsigned int efexid) {
+  m_eFEX_ID = efexid;
+  return m_eFEX_ID; 
+}
+
+bool LVL1::eFEXegTOB::setSeedUnD(bool seedund) {
+  m_seed_UnD = seedund;
+  return m_seed_UnD;
+}
+
+unsigned int LVL1::eFEXegTOB::setSeed(unsigned int seed) {
+  m_seed = seed;
+  return m_seed;
+}
+
+unsigned int LVL1::eFEXegTOB::setRetaNum(unsigned int retaNum) {
+  m_Reta_Num = retaNum;
+  return m_Reta_Num;
+}
+
+unsigned int LVL1::eFEXegTOB::setRetaDen(unsigned int retaDen) {
+  m_Reta_Den = retaDen;
+  return m_Reta_Den;
+}
+
+unsigned int LVL1::eFEXegTOB::setRhadNum(unsigned int rhadNum) {
+  m_Rhad_Num = rhadNum;
+  return m_Rhad_Num;
+}
+
+unsigned int LVL1::eFEXegTOB::setRhadDen(unsigned int rhadDen) {
+  m_Rhad_Den = rhadDen;
+  return m_Rhad_Den;
+}
+
+unsigned int LVL1::eFEXegTOB::setWstotNum(unsigned int wstot_Num) {
+  m_Wstot_Num = wstot_Num;
+  return m_Wstot_Num;
+}
+
+unsigned int LVL1::eFEXegTOB::setWstotDen(unsigned int wstot_Den) {
+  m_Wstot_Den = wstot_Den;
+  return m_Wstot_Den;
+}
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauAlgo.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauAlgo.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..aa9c139cb9286bf2f5ac723f8a348ed603d05bed
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauAlgo.cxx
@@ -0,0 +1,280 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//*************************************************************************
+//                          eFEXtauAlgo  -  description
+//                             --------------------
+//    begin                 : 06 05 2020
+//    email                 : nicholas.andrew.luongo@cern.ch
+//*************************************************************************
+
+#include <iostream>
+
+#include "L1CaloFEXSim/eFEXtauAlgo.h"
+#include "L1CaloFEXSim/eFEXtauTOB.h"
+#include "L1CaloFEXSim/eTower.h"
+
+  // default constructor for persistency
+LVL1::eFEXtauAlgo::eFEXtauAlgo(const std::string& type, const std::string& name, const IInterface* parent):
+    AthAlgTool(type, name, parent)
+  {
+    declareInterface<IeFEXtauAlgo>(this);
+  }
+
+  /** Destructor */
+LVL1::eFEXtauAlgo::~eFEXtauAlgo()
+{
+}
+
+StatusCode LVL1::eFEXtauAlgo::initialize()
+{
+
+  return StatusCode::SUCCESS;
+
+}
+
+StatusCode LVL1::eFEXtauAlgo::safetyTest(){
+
+  // This is to test that it will also work in the other functions, as we cal this object from SG in every function but don't want them all to have to return StatusCodes, and i'm not sure how to make this a private member instead
+  ATH_CHECK(m_eFEXtauAlgo_eTowerContainerKey.initialize());
+  SG::ReadHandle<eTowerContainer> jk_eFEXtauAlgo_eTowerContainer(m_eFEXtauAlgo_eTowerContainerKey/*,ctx*/);
+  if(!jk_eFEXtauAlgo_eTowerContainer.isValid()){
+    ATH_MSG_FATAL("LVL1::eFEXtauAlgo::safetyTest() Could not retrieve jk_eFEXtauAlgo_eTowerContainer " << m_eFEXtauAlgo_eTowerContainerKey.key() );
+    return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+
+}
+
+void LVL1::eFEXtauAlgo::setup(int inputTable[3][3]){
+
+  std::copy(&inputTable[0][0], &inputTable[0][0] + 9, &m_eFexalgoTowerID[0][0]);
+
+  buildLayers();
+  setSupercellSeed();
+  setUnDAndOffPhi();
+
+}
+
+LVL1::eFEXtauTOB *LVL1::eFEXtauAlgo::getTauTOB()
+{
+  eFEXtauTOB *tob = new eFEXtauTOB();
+  unsigned int et = getEt();
+  tob->setEt(et);
+  tob->setBitwiseEt(getBitwiseEt());
+  tob->setIso(getIso());
+  tob->setSeedUnD(getUnD());
+  return tob;
+}
+
+// Build arrays holding cell ETs for each layer plus entire tower
+void LVL1::eFEXtauAlgo::buildLayers()
+{
+
+  SG::ReadHandle<eTowerContainer> jk_eFEXtauAlgo_eTowerContainer(m_eFEXtauAlgo_eTowerContainerKey/*,ctx*/);
+
+  for(unsigned int ieta = 0; ieta < 3; ieta++)
+    {
+      for(unsigned int iphi = 0; iphi < 3; iphi++)
+        {
+	  const LVL1::eTower * tmpTower = jk_eFEXtauAlgo_eTowerContainer->findTower(m_eFexalgoTowerID[iphi][ieta]);
+	  m_twrcells[ieta][iphi] = tmpTower->getTotalET();
+	  m_em0cells[ieta][iphi] = tmpTower->getLayerTotalET(0);
+	  m_em3cells[ieta][iphi] = tmpTower->getLayerTotalET(3);
+	  m_hadcells[ieta][iphi] = tmpTower->getLayerTotalET(4);
+	  for(unsigned int i = 0; i < 4; i++)
+            {
+	      m_em1cells[4 * ieta + i][iphi] = tmpTower->getET(1, i);
+	      m_em2cells[4 * ieta + i][iphi] = tmpTower->getET(2, i);
+            }
+        }
+    }
+  m_cellsSet = true;
+
+}
+
+// Check if central tower qualifies as a seed tower for the tau algorithm
+bool LVL1::eFEXtauAlgo::isCentralTowerSeed()
+{
+  // Need layer cell ET arrays to be built
+  if (m_cellsSet == false){
+    ATH_MSG_DEBUG("Layers not built, cannot accurately determine if a seed tower.");
+  }
+  
+  bool out = true;
+  
+  // Get central tower ET
+  unsigned int centralET = m_twrcells[1][1];
+  
+  // Enforce minimum of 1 GeV in central tower
+  if (centralET < 1000.){
+    out = false;
+  }
+  
+  // Loop over all cells and check that the central tower is a local maximum
+  for (unsigned int beta = 0; beta < 3; beta++)
+  {
+    for (unsigned int bphi = 0; bphi < 3; bphi++)
+    {
+      // Don't need to compare central cell with itself
+      if ((beta == 1) && (bphi == 1)){
+        continue;
+      }
+      
+      // Cells to the up and right must have strictly lesser ET
+      if (((beta == 0) && (bphi == 0)) || ((beta == 1) && (bphi == 0)) || ((beta == 2) && (bphi == 0)) || ((beta == 2) && (bphi == 1)))
+	{
+	  if (centralET <= m_twrcells[beta][bphi]){
+	    out = false;
+	  }
+	}
+    }
+  }
+  
+  return out;
+}
+
+// Calculate reconstructed ET value
+unsigned int LVL1::eFEXtauAlgo::getEt()
+{
+  if (m_cellsSet == false){
+    ATH_MSG_DEBUG("Layers not built, cannot accurately calculate Et.");
+  }
+
+  unsigned int out = 0;
+
+  out += m_em0cells[0][1];
+  out += m_em0cells[1][1];
+  out += m_em0cells[2][1];
+  out += m_em0cells[0][m_offPhi];
+  out += m_em0cells[1][m_offPhi];
+  out += m_em0cells[2][m_offPhi];
+
+  out += m_em1cells[m_seed][1];
+  out += m_em1cells[m_seed + 1][1];
+  out += m_em1cells[m_seed + 2][1];
+  out += m_em1cells[m_seed - 1][1];
+  out += m_em1cells[m_seed - 2][1];
+  out += m_em1cells[m_seed][m_offPhi];
+  out += m_em1cells[m_seed + 1][m_offPhi];
+  out += m_em1cells[m_seed + 2][m_offPhi];
+  out += m_em1cells[m_seed - 1][m_offPhi];
+  out += m_em1cells[m_seed - 2][m_offPhi];
+
+  out += m_em2cells[m_seed][1];
+  out += m_em2cells[m_seed + 1][1];
+  out += m_em2cells[m_seed + 2][1];
+  out += m_em2cells[m_seed - 1][1];
+  out += m_em2cells[m_seed - 2][1];
+  out += m_em2cells[m_seed][m_offPhi];
+  out += m_em2cells[m_seed + 1][m_offPhi];
+  out += m_em2cells[m_seed + 2][m_offPhi];
+  out += m_em2cells[m_seed - 1][m_offPhi];
+  out += m_em2cells[m_seed - 2][m_offPhi];
+
+  out += m_em3cells[0][1];
+  out += m_em3cells[1][1];
+  out += m_em3cells[2][1];
+  out += m_em3cells[0][m_offPhi];
+  out += m_em3cells[1][m_offPhi];
+  out += m_em3cells[2][m_offPhi];
+
+  out += m_hadcells[0][1];
+  out += m_hadcells[1][1];
+  out += m_hadcells[2][1];
+  out += m_hadcells[0][m_offPhi];
+  out += m_hadcells[1][m_offPhi];
+  out += m_hadcells[2][m_offPhi];
+
+  return out;
+}
+
+// Calculate isolation variable
+float LVL1::eFEXtauAlgo::getIso()
+{
+  if (m_cellsSet == false){
+    ATH_MSG_DEBUG("Layers not built, cannot accurately calculate isolation.");
+  }
+
+  unsigned int isoInner = 0;
+
+  isoInner += m_em2cells[m_seed][1];
+  isoInner += m_em2cells[m_seed + 1][1];
+  isoInner += m_em2cells[m_seed - 1][1];
+  isoInner += m_em2cells[m_seed][m_offPhi];
+  isoInner += m_em2cells[m_seed + 1][m_offPhi];
+  isoInner += m_em2cells[m_seed - 1][m_offPhi];
+
+  unsigned int isoOuter = isoInner;
+
+  isoOuter += m_em2cells[m_seed + 2][1];
+  isoOuter += m_em2cells[m_seed - 2][1];
+  isoOuter += m_em2cells[m_seed + 3][1];
+  isoOuter += m_em2cells[m_seed - 3][1];
+  isoOuter += m_em2cells[m_seed + 4][1];
+  isoOuter += m_em2cells[m_seed - 4][1];
+  isoOuter += m_em2cells[m_seed + 2][m_offPhi];
+  isoOuter += m_em2cells[m_seed - 2][m_offPhi];
+  isoOuter += m_em2cells[m_seed + 3][m_offPhi];
+  isoOuter += m_em2cells[m_seed - 3][m_offPhi];
+  isoOuter += m_em2cells[m_seed + 4][m_offPhi];
+  isoOuter += m_em2cells[m_seed - 4][m_offPhi];
+
+  float out = (float)isoInner / (float)isoOuter;
+  return out;
+}
+
+// Set the off phi value used to calculate ET and isolation
+void LVL1::eFEXtauAlgo::setUnDAndOffPhi()
+{
+  if (m_cellsSet == false){ 
+    ATH_MSG_DEBUG("Layers not built, cannot accurately set phi direction.");
+  }  
+
+  unsigned int upwardEt = 0;
+  upwardEt += m_em2cells[m_seed][2];
+  upwardEt += m_em1cells[m_seed][2];
+  
+  unsigned int downwardEt = 0;
+  downwardEt += m_em2cells[m_seed][0]; 
+  downwardEt += m_em1cells[m_seed][0];
+
+  if (downwardEt > upwardEt)
+  {
+    m_offPhi = 0;
+    m_und = false;
+  }
+}
+
+// Find the supercell seed eta value, must be in central cell so in the range 4-7 inclusive
+void LVL1::eFEXtauAlgo::setSupercellSeed()
+{
+  unsigned int seed = 4;
+  int max_et = 0;
+  int cell_et = 0;
+  for(unsigned int i = 4; i < 8; i++)
+  {
+    cell_et = m_em2cells[i][1];
+    if (cell_et > max_et)
+    {
+      seed = i;
+      max_et = cell_et;
+    }
+  }
+  m_seed = seed;
+}
+
+// Return the bitwise value of the given Et
+// See eFEXtauBaseAlgo for a first attempt at this
+unsigned int LVL1::eFEXtauAlgo::getBitwiseEt()
+{
+    unsigned int out = 0;
+    return out;
+}
+
+bool LVL1::eFEXtauAlgo::getUnD()
+{
+    return m_und;
+}
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauTOB.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauTOB.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d870250350b1ed6e09b32601827149ae149991c1
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauTOB.cxx
@@ -0,0 +1,120 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXtauTOB.cxx  -  
+//                              -------------------
+//     begin                : 17 01 2020
+//     email                : nicholas.andrew.luongo@cern.ch
+//  **************************************************************************
+
+
+#include "L1CaloFEXSim/eFEXtauTOB.h"
+
+
+LVL1::eFEXtauTOB::eFEXtauTOB():
+	m_eta{99999},
+	m_phi{99999},
+	m_et{99999},
+	m_reta_num{99999},
+	m_reta_den{99999},
+	m_rhad_num{99999},
+	m_rhad_den{99999},
+	m_wstot_num{99999},
+	m_wstot_den{99999},
+	m_fpga_id{99999},
+	m_efex_id{99999},
+	m_seed_und{1},
+	m_seed{99999}
+{}
+
+unsigned int LVL1::eFEXtauTOB::setEta(unsigned int eta)
+{
+	m_eta = eta;
+	return m_eta;
+}
+
+unsigned int LVL1::eFEXtauTOB::setPhi(unsigned int phi)
+{
+	m_phi = phi;
+	return m_phi;
+}
+
+unsigned int LVL1::eFEXtauTOB::setEt(unsigned int et)
+{
+	m_et = et;
+	return m_et;
+}
+
+unsigned int LVL1::eFEXtauTOB::setBitwiseEt(unsigned int bitwise_et)
+{
+	m_bitwise_et = bitwise_et;
+	return m_bitwise_et;
+}
+
+float LVL1::eFEXtauTOB::setIso(unsigned int iso)
+{
+	m_iso = iso;
+	return m_iso;
+}
+
+unsigned int LVL1::eFEXtauTOB::setFPGAID(unsigned int fpgaid)
+{
+	m_fpga_id = fpgaid;
+	return m_fpga_id; 
+}
+
+unsigned int LVL1::eFEXtauTOB::setEFEXID(unsigned int efexid)
+{
+	m_efex_id = efexid;
+	return m_efex_id; 
+}
+
+bool LVL1::eFEXtauTOB::setSeedUnD(bool seedund)
+{
+	m_seed_und = seedund;
+	return m_seed_und;
+}
+
+unsigned int LVL1::eFEXtauTOB::setSeed(unsigned int seed)
+{
+	m_seed = seed;
+	return m_seed;
+}
+
+unsigned int LVL1::eFEXtauTOB::setRetaNum(unsigned int retanum)
+{
+	m_reta_num = retanum;
+	return m_reta_num;
+}
+
+unsigned int LVL1::eFEXtauTOB::setRetaDen(unsigned int retaden)
+{
+	m_reta_den = retaden;
+	return m_reta_den;
+}
+
+unsigned int LVL1::eFEXtauTOB::setRhadNum(unsigned int rhadnum)
+{
+	m_rhad_num = rhadnum;
+	return m_rhad_num;
+}
+
+unsigned int LVL1::eFEXtauTOB::setRhadDen(unsigned int rhadden)
+{
+	m_rhad_den = rhadden;
+	return m_rhad_den;
+}
+
+unsigned int LVL1::eFEXtauTOB::setWstotNum(unsigned int wstot_num)
+{
+	m_wstot_num = wstot_num;
+	return wstot_num;
+}
+
+unsigned int LVL1::eFEXtauTOB::setWstotDen(unsigned int wstot_den)
+{
+	m_wstot_den = wstot_den;
+	return wstot_den;
+}
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eSuperCellTowerMapper.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eSuperCellTowerMapper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..26f61e7fbe3e21237eb193a95edde59a808690ad
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eSuperCellTowerMapper.cxx
@@ -0,0 +1,773 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "xAODTrigL1Calo/TriggerTowerContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "L1CaloFEXSim/eTowerBuilder.h"
+#include "TROOT.h"
+#include "TH1.h"
+#include "TH1F.h"
+#include "TPad.h"
+#include "TCanvas.h"
+#include "L1CaloFEXSim/eSuperCellTowerMapper.h"
+#include "GaudiKernel/MsgStream.h"
+#include "AthenaKernel/errorcheck.h"
+
+//using Athena_test::URNG;
+//using Athena_test::randi_seed;
+//using Athena_test::randf_seed;
+
+// This is a class which is designed to receive in a list of supercells and a list of eTowers and match them together appropriately.
+
+
+/* VERY IMPORTANT NOTE.  ARE YOU CONFUSED ABOUT SAMPLING IDs? WANT TO KNOW WHERE ON EARTH THEY COME FROM? FINDING OBSCURE VALUES THAT ARE APPARENTLY MEANINGLESS?
+
+LOOK HERE!: athena/Calorimeter/CaloGeoHelpers/CaloGeoHelpers/CaloSampling.def
+
+*/
+
+
+namespace LVL1 {
+
+eSuperCellTowerMapper::eSuperCellTowerMapper(const std::string& type,const std::string& name,const IInterface* parent):
+  AthAlgTool(type,name,parent)
+{
+  declareInterface<IeSuperCellTowerMapper>(this);
+
+}
+
+eSuperCellTowerMapper::~eSuperCellTowerMapper()
+{
+
+}
+
+StatusCode eSuperCellTowerMapper::initialize()
+{
+ 
+  ATH_CHECK( m_scellsCollectionSGKey.initialize() );
+  ATH_CHECK( m_triggerTowerCollectionSGKey.initialize() );
+
+  return StatusCode::SUCCESS;
+    
+}
+
+StatusCode eSuperCellTowerMapper::AssignTriggerTowerMapper(/*eTowerContainer* my_eTowerContainerRaw*/ std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw){
+  
+  SG::ReadHandle<xAOD::TriggerTowerContainer> jk_triggerTowerCollection(m_triggerTowerCollectionSGKey/*,ctx*/);
+  if(!jk_triggerTowerCollection.isValid()){
+    ATH_MSG_FATAL("Could not retrieve jk_triggerTowerCollection " << m_triggerTowerCollectionSGKey.key() );
+    return StatusCode::FAILURE;
+  }
+
+  for(auto eachTower : *jk_triggerTowerCollection) {
+    if(fabs(eachTower->eta())<1.5 && eachTower->sampling()==1) {
+      int i_phi = int(eachTower->phi()/(3.14159/32));
+      int etaSign{-1};
+      int towerID_Modifier{100000};
+      if (eachTower->eta() > 0) {
+        etaSign = 1;
+        towerID_Modifier = 200000;
+      }
+      int i_eta = int(eachTower->eta() * 10) * etaSign;
+      if(i_eta * etaSign == -14) {
+        towerID_Modifier = 300000;
+      } else if (i_eta * etaSign == 14) {
+        towerID_Modifier = 400000;
+      }
+
+      int towerid = FindTowerIDForSuperCell(i_eta, i_phi) + towerID_Modifier;
+      LVL1::eTower * targetTower; 
+      if((targetTower = my_eTowerContainerRaw->findTower(towerid))) {
+        if (targetTower->getET_float(4, 0) > 0) {
+          ATH_MSG_WARNING("\n==== eSuperCellTowerMapper ============ Hadronic layer energy filled more than once - it will be ignored. (Needs investigation).  Please report this!");
+        }
+        targetTower->setET(10, int(eachTower->cpET()) * 0.5 * 1000., 4);
+      } else {
+        ATH_MSG_WARNING("\n==== eSuperCellTowerMapper ============ Tower id is officially unknown - it will be ignored. (Needs investigation).  Please report this!");
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+void eSuperCellTowerMapper::reset(){
+  return;
+}
+
+  // works for real supercells from MC
+  StatusCode eSuperCellTowerMapper::AssignSuperCellsToTowers(/*eTowerContainer* my_eTowerContainerRaw*/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw)
+{
+
+  bool doPrint = false;
+
+  SG::ReadHandle<CaloCellContainer> jk_scellsCollection(m_scellsCollectionSGKey/*,ctx*/);
+  if(!jk_scellsCollection.isValid()){
+    ATH_MSG_FATAL("Could not retrieve jk_scellsCollection " << m_scellsCollectionSGKey.key() );
+    return StatusCode::FAILURE;
+  }
+
+
+  //const CaloCell_Base_ID* idHelper = caloIdManager->getCaloCell_SuperCell_ID(); // getting the id helper class
+  const CaloCell_Base_ID* idHelper = nullptr;
+  ATH_CHECK( detStore()->retrieve (idHelper, "CaloCell_SuperCell_ID") );
+
+  for (CaloCellContainer::const_iterator cell = jk_scellsCollection->begin(); cell != jk_scellsCollection->end(); ++cell){
+    const CaloSampling::CaloSample sample = (*cell)->caloDDE()->getSampling();
+    const Identifier ID = (*cell)->ID(); // super cell unique ID
+    int region = idHelper->region(ID);
+    int layer = -1;
+    int pos_neg = idHelper->pos_neg(ID);
+    int eta_index = idHelper->eta(ID);
+    const int phi_index = idHelper->phi(ID);
+    float et = (*cell)->energy();
+    int prov = (*cell)->provenance();
+
+    /*
+  CaloSampling:
+    PreSamplerB  0
+           EMB1  1
+           EMB2  2
+           EMB3  3
+
+    PreSamplerE  4
+           EME1  5
+           EME2  6
+           EME3  7
+
+           HEC0  8
+           HEC1  9
+           HEC2  10
+           HEC3  11
+    */
+
+    //We need to explicitly avoid +/- 3 pos_neg supercells! These go beyond |eta| == 2.5
+    if(abs(pos_neg) == 3){ continue; }
+
+    // LOCAL TO GLOBAL ETA INDEX PATCH - USE A 'TOWER OFFSET' TO MARK THE START OF THE ETA_INDEX COUNTING (e.g. the rounded eta value of the innermost supercell)
+    switch(sample){
+    case CaloSampling::PreSamplerB: { break; }
+    case CaloSampling::EMB1: {
+      if(region == 1){ eta_index += 56; }
+      break;
+    }
+    case CaloSampling::EMB2: {
+      if(region == 1){ eta_index += 56; }
+      break;
+    }
+    case CaloSampling::EMB3: { break; }
+    case CaloSampling::PreSamplerE: { eta_index += 15; break; }
+    case CaloSampling::EME1: {
+      if(region == 0){ eta_index += 14; }
+      else if (region == 1){ /* doesn't exist */ }
+      else if (region == 2){ eta_index += 60; }
+      else if (region == 3){ eta_index += 108; } //6 supercell region
+      else if (region == 4){ eta_index += 80; }
+      else if (region == 5){ eta_index += 24; }
+      break;
+    }
+    case CaloSampling::EME2: {
+      if(region == 0){ eta_index += 14; }
+      else if (region == 1){ eta_index += 57; }
+      break;
+    }
+    case CaloSampling::EME3: { eta_index += 15; break; }
+    case CaloSampling::HEC0:
+    case CaloSampling::HEC1:
+    case CaloSampling::HEC2:
+    case CaloSampling::HEC3: { eta_index += 15; break; }
+    default: { /*ATH_MSG_DEBUG("Not doing anything since sample = " << sample);*/ break; }
+    }
+
+
+    FindAndConnectTower(my_eTowerContainerRaw,sample,region,layer,pos_neg,eta_index,phi_index,ID,et,prov,doPrint);
+  }
+  
+  return StatusCode::SUCCESS;
+  
+}
+
+
+  int eSuperCellTowerMapper::ConnectSuperCellToTower(/*eTowerContainer* my_eTowerContainerRaw*/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw,int iETower, Identifier ID, int iCell, float et, int layer, bool doenergysplit){
+
+  if(my_eTowerContainerRaw->findTower(iETower)){
+    (my_eTowerContainerRaw->findTower(iETower))->setSCID(ID,iCell,et,layer,doenergysplit);
+  }
+
+  return 1;
+
+}
+
+  int eSuperCellTowerMapper::FindAndConnectTower(/*eTowerContainer* my_eTowerContainerRaw*/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw,CaloSampling::CaloSample sample,const int region, int layer, const int pos_neg, const int eta_index, const int phi_index, Identifier ID, float et, int prov,bool doPrint)
+{
+
+  // bool for the special case of 1.8 < eta < 2.0 only in the front layer
+  bool doenergysplit = false;
+  
+  // bool as a flag to enable or disable the connection of supercells to towers according to their location and identities
+  bool validcell = true;
+
+  // We tell the eTower which supercell unique ID is in each of it's available 'slots'
+  int towereta = -99; // to be filled with tower eta value to help find it
+  int towerphi = -99; // to be filled with tower phi value to help find it
+  int iETower = -99; // The tower ID which the supercell will be assigned to
+  int iCell = -1; // The position within the Tower that the supercell will be assigned to
+  int towerID_Modifier = -999999999; // adjustable tower ID modifier to fit tower Id scheme
+
+  /*    
+  ** iCell Numbering Scheme **
+  
+  Let's use the following scheme (from low to high eta regardless of detector side):
+  Layer 0:  Cell 0
+  Layer 1:  Cell 1, 2, 3, 4
+  Layer 2:  Cell 5, 6, 7, 8
+  Layer 3:  Cell 9
+  Layer 4:  Cell 10 (HEC or TILE, if we have them!)
+  */
+  
+
+  /*
+  ** Structure of the EMB in Supercells **
+  
+  0 < 1.4 in steps of 0.1 == 14 towers
+  1.4 < 1.52 in steps of 0.12  ==> THIS TOWER IS MOVED TO TRANS TOWER REGION
+  14 towers total (all by presampler)
+  64 towers in phi in total
+  
+  896 towers in EMB per side
+  1792 towers in EMB total  
+  */
+  
+  /*
+  ** Structure of the TRANS in Supercells **
+
+  1.4 < 1.5, 1 special tower made from EMB and EME supercells together
+  1 tower in eta
+  64 towers in phi
+
+  64 towers in TRANS total
+  */
+
+  /*
+  ** Structure of the EMEC in Supercells **
+  
+  1.375 < 1.5, funny behaviour, treated as 1 special tower ==> 1 tower === TRANSITION TOWER NOW!
+  1.5 < 1.8 standard towers by presampler ==> 3 towers
+  1.8 < 2.0 standard towers by back ==> 2 towers
+  2.0 < 2.4 standard towers by back ==> 4 towers
+  2.4 < 2.5 standard tower by back ==> 1 tower
+  2.5 < 3.1, funny behaviour, treated as 3 wide towers ==> 3 towers.   Also wide in phi!  ===> WE DON'T CARE ABOUT |ETA| > 2.5
+  3.1 < 3.2 standard tower by back ==> 1 tower.  Also wide in phi!  ===> WE DON'T CARE ABOUT |ETA| > 2.5
+  10 towers in eta in total (by different means) (IGNORING ABOVE |ETA| > 2.5)
+  64 towers initially in phi (IGNORING ABOVE |ETA| > 2.5)
+  
+  640 towers in EME per side
+  1280 towers in EME total  
+  */
+  
+
+  /*
+  ** Structure of the HEC in Supercells **
+  
+  1.5 - 2.5, [Region 0] standard towers by presampler ==> layer on top of existing towers
+  
+  */
+  
+  /*
+  ** Notes on overall structure **
+    Total number of expected towers can be as high as: 896+640 = 1536 per side + 64 transition region towers (TRANS) each side = 3200 total <=== This is the correct value!
+  */
+
+  /*
+  ** Notes on Tower ID Number Scheme **
+
+    Left Barrel IETower = 100000 + X
+    Right Barrel IETower = 200000 + X
+    Left TRANS IETower = 300000 + X;
+    Right TRANS IETower = 400000 + X;
+    Left Endcap IETower = 500000 + X
+    Right Endcap IETower = 600000 + X
+    Left Hadronic Endcap IETower =  11100000 + X --> These are just Layer 5 of Endcap Towers.  They will never be generated as standalone eTowers.
+    Right Hadronic Endcap IETower =  22200000 + X --> These are just Layer 5 of Endcap Towers.  They will never be generated as standalone eTowers.
+
+  */
+
+
+  //----------------------------------------------------------
+
+  // Begin assigning supercells to Towers
+
+  //----------------------------------------------------------
+
+  switch (sample) {
+    // E.M. Barrel (EMB)
+  case CaloSampling::PreSamplerB: { // DONE
+    // Presampler of the EMBarrel.  Supercells are 0.1 x 0.1 unless stated otherwise
+    // Region 0 has 14 supercells in 0 < eta < 1.4 and 64 supercells in phi.
+    // Region 0 has 1 supercell (0.12 x 0.1) in 1.4 < eta < 1.52 and 64 supercells in phi.  // Documentation describes this as Region 1 but the code does not. We go with Region 0.
+
+    layer = 0; // By definition
+    
+    towereta = eta_index; // Layer 0 has super cells which are 0.1 x 0.1 - i.e. the full width of a tower - sothe eta_index matches up to the Tower Eta
+    towerphi = phi_index; // phi is standard also
+    
+    if(eta_index == 14){ // special treatment for TRANSITION tower
+      if(pos_neg < 0){ towerID_Modifier = 300000; }
+      else if(pos_neg > 0){ towerID_Modifier = 400000; }
+      iCell = 0; // By definition
+    }
+    else{ // standard treatment for non-transition towers
+      if(pos_neg < 0){ towerID_Modifier = 100000; }
+      else if(pos_neg > 0){ towerID_Modifier = 200000; }
+      iCell = 0; // By definition
+    }
+
+    break;
+  }
+  case CaloSampling::EMB1: 
+  case CaloSampling::EMB2: {
+    // Layer 1 of the EMBarrel.  Supercells are 0.025 x 0.1 unless stated otherwise
+    // Region 0 has 56 supercells in 0 < eta < 1.4 and 64 supercells in phi.
+    // Region 1 has 3 supercells in 1.4 < eta < 1.475 and 64 supercells in phi.
+    
+    // Layer 2 of the EMBarrel.  Supercells are 0.025 x 0.1 unless stated otherwise
+    // Region 0 has 56 supercells in 0 < eta < 1.4 and 64 supercells in phi.
+    // Region 1 has 1 supercells (0.075 x 0.1) in 1.4 < eta < 1.475 and 64 supercells in phi.
+
+    if (region == 0) {
+      towereta = eta_index / 4; // this divides integers by 4 and truncates away the decimals (rounds DOWN to an integer)
+      towerphi = phi_index;
+      if(pos_neg < 0){ towerID_Modifier = 100000; }
+      else if(pos_neg > 0){ towerID_Modifier = 200000; }
+    }
+    else if (region == 1){
+      towereta = 14; // hardcoded but is correct
+      towerphi = phi_index;
+      if(pos_neg < 0){ towerID_Modifier = 300000; }
+      else if(pos_neg > 0){ towerID_Modifier = 400000; }
+    }
+    else {
+      ATH_MSG_DEBUG("[CaloSampling::EMB1 or CaloSampling::EMB2] -> invalid 'region' value: " << region << " (Under investigation) ");
+    }
+
+    switch(sample){
+    case CaloSampling::EMB1: { 
+      iCell = (eta_index % 4) + 1; 
+      layer = 1; 
+      break;
+    }
+    case CaloSampling::EMB2: { 
+      if (region == 0) { iCell = (eta_index % 4) + 5; }
+      else if (region == 1){ iCell = 5; }
+      layer  = 2; 
+      break;
+    }
+    default: {
+      ATH_MSG_DEBUG("CaloSampling::EMBX -> invalid sample for assigning iCell value! " << sample << " (Under investigation) ");
+      break;
+    }
+    }
+
+    break;
+  }
+  case CaloSampling::EMB3: {
+    // Layer 3 of the EMBarrel.  Supercells are 0.1 x 0.1 unless stated otherwise
+    // Region 0 has 14 supercells in 0 < eta < 1.4 and 64 supercells in phi.
+    // Region 1 does not exist
+    
+    layer = 3; // By definiton
+    towereta = eta_index; // Analogous to PreSamplerB
+    towerphi = phi_index;
+    
+    iCell = 9; // By definition;
+    
+    if(pos_neg < 0){ towerID_Modifier = 100000; }
+    else if(pos_neg > 0){ towerID_Modifier = 200000; }
+    
+    break;
+  }
+    // E.M. End-cap (EMEC)
+  case CaloSampling::PreSamplerE: {
+    // Region 1 has 3 supercells in 1.5 < eta < 1.8, and 64 supercells in phi.
+    // Supercells are 0.1 x 0.1.
+    
+    layer = 0;
+
+    towereta = eta_index;
+    towerphi = phi_index;
+    
+    iCell = 0; // By definition
+    
+    if(pos_neg < 0){ towerID_Modifier = 500000; }
+    else if(pos_neg > 0){ towerID_Modifier = 600000; }
+    
+    break;
+  }
+  case CaloSampling::EME1: {
+    // Layer 1 of the EM End-Cap.  Supercells very frequently change in size.
+    // Region 0 has 1 supercell in 1.375 < eta < 1.5, and 64 supercells in phi.  Supercells are 0.125 x 0.1.
+    // Region 1 has 12 supercells in 1.5 < eta < 1.8, and 64 supercells in phi.  Supercells are 0.025 x 0.1.
+    // Region 2 has 6 (now 12??) supercells in 1.8 < eta < 2.0, and 64 supercells in phi.  Supercells are 0.0333 (0.016667 ???) x 0.1.
+    // Region 3 has 16 supercells in 2.0 < eta < 2.4, and 64 supercells in phi.  Supercells are 0.025 x 0.1.
+    // Region 4 has 1 supercell in 2.4 < eta < 2.5, and 64 supercells in phi.  Supercells are 0.1 x 0.1.
+    // Region 5 has 3 supercells in 2.5 < eta < 3.1, and 32 supercells in phi.  Supercells are 0.2 x 0.2.
+    // Region 6 has 1 supercell in 3.1 < eta < 3.2, and 32 supercells in phi.  Supercells are 0.1 x 0.2
+    
+    // 1.375 < 1.5, funny behaviour, treated as 1 special tower ==> 1 tower
+    // 1.5 < 1.8 standard towers by presampler ==> 3 towers
+    // 1.8 < 2.0 standard towers by back ==> 2 towers
+    // 2.0 < 2.4 standard towers by back ==> 4 towers
+    // 2.4 < 2.5 standard tower by back ==> 1 tower
+    // 2.5 < 3.1, funny behaviour, treated as 3 wide towers ==> 3 towers
+    // 3.1 < 3.2, funny behaviour, treated as 1 tower ==> 1 tower
+    // 15 towers in total (by different means)
+    
+    layer = 1; // By definition
+    
+    switch (region) {
+    case 0: { // special treatment for transition region
+      
+      towereta = eta_index;
+      towerphi = phi_index;
+
+      iCell = 4; // Placement based on advice from Alan Watson
+      break;
+    }
+    case 2: {
+
+      towereta = (eta_index / 4);
+      towerphi = phi_index;
+      
+      iCell = (eta_index % 4) + 1;
+      break;
+    }
+    case 3: {
+
+      // calc ID
+      towereta = (eta_index / 6);
+      towerphi = phi_index;
+      
+      iCell = (eta_index % 6) + 1;
+
+      if(iCell == 1){ iCell = 1; doenergysplit = false; }
+      else if( iCell == 2 ){ iCell = 1; doenergysplit = true; }
+      else if( iCell == 3 ){ iCell = 2; doenergysplit = false; }
+      else if( iCell == 4 ){ iCell = 3; doenergysplit = false; }
+      else if( iCell == 5 ){ iCell = 3; doenergysplit = true; }
+      else if( iCell == 6 ){ iCell = 4; doenergysplit = false; }
+
+      break;
+
+      // OUTDATED CODE LEFT HERE AS A FRIENDLY REMINDER OF SPECIAL STRUCTURE INCASE A FUTURE ISSUE ARISES======================
+      // Begin Dima---
+      // This is the special region, with 6 supercells per tower
+      // Idea here is to divide 2 out of 6 by 2 and add half ET to each of 2 "normal" SC
+      //iETower = (eta_index / 6) + 18;
+
+      // These are the cells we will split
+      //if (eta_index % 3 == 1) {
+      //iCell = (eta_index % 6 < 3 ? 0 : 2);
+      //iCell2 = iCell + 1;
+      //} else {
+      // These ones just need assigning to the correct location
+      // So that 0, 2, 3, 5 => 0, 1, 2, 3
+      //iCell = (eta_index % 6) / 1.45;
+      //}
+      // end DIMA---
+      // ======================================================================================================================
+    }
+    case 4: {
+
+      towereta = (eta_index / 4);
+      towerphi = phi_index;
+      
+      iCell = (eta_index % 4) + 1;
+      break;
+    }
+    case 5: {
+
+      towereta = eta_index ;
+      towerphi = phi_index;
+      
+      iCell = 1;
+      break;
+    }
+    default: {
+      // This should never fire because we don't go beyond 2.5 
+      ATH_MSG_DEBUG("CaloSampling::EME1 -> invalid 'region' value: " << region << " (Under investigation) ");
+      break;
+    }
+      break;
+    }
+
+    if(region != 0){
+      if(pos_neg < 0){ towerID_Modifier = 500000; }
+      else if(pos_neg > 0){ towerID_Modifier = 600000; }
+    }
+    else if(region == 0){
+      // TRANSITION REGION TREATMENT!
+      if(pos_neg < 0){ towerID_Modifier = 300000; }
+      else if(pos_neg > 0){ towerID_Modifier = 400000; }
+    }
+
+    break;
+  }
+  case CaloSampling::EME2: {
+    
+    // Layer 2 of the EM End-Cap.  Supercells very frequently change in size.
+    // Region 0 has 1 supercell in 1.375 < eta < 1.425, and 64 supercells in phi.  Supercells are 0.05 x 0.1.
+    // Region 0 also has 3 supercells in 1.425 < eta < 1.5, and 64 supercells in phi.  Supercells are 0.025 x 0.1
+    // Region 1 has 12 supercells in 1.5 < eta < 1.8, and 64 supercells in phi.  Supercells are 0.025 x 0.1.
+    // Region 2 has 8 supercells in 1.8 < eta < 2.0, and 64 supercells in phi.  Supercells are 0.025 x 0.1.
+    // Region 3 has 16 supercells in 2.0 < eta < 2.4, and 64 supercells in phi.  Supercells are 0.025 x 0.1.
+    // Region 4 has 4 supercells in 2.4 < eta < 2.5, and 64 supercells in phi.  Supercells are 0.025 x 0.1.
+    // Region 5 has 3 supercells in 2.5 < eta < 3.1, and 32 supercells in phi.  Supercells are 0.2 x 0.2.
+    // Region 6 has 1 supercell in 3.1 < eta < 3.2, and 32 supercells in phi.  Supercells are 0.1 x 0.2
+    
+    layer = 2;
+    
+    switch (region) {
+    case 0: { // special treatment for TRANSITON region
+
+      layer = 3; // change layer label for ET threshold treatment since we are treating this as a layer3 cell - it's an extreme special case cell as part of tne transition region
+
+      towereta = eta_index;
+      towerphi = phi_index;
+
+      iCell = 9;
+
+      break;
+    }
+    case 1: {
+
+      towereta = (eta_index / 4);
+      towerphi = phi_index;
+      
+      iCell = (eta_index % 4) + 5;
+     
+      break;
+    }
+    default: {
+      ATH_MSG_DEBUG("CaloSampling::EME2 -> invalid 'region' value: " << region << " (Under investigation) ");
+      break;
+    }
+      break;
+    }
+    
+    if(region == 0){
+      // TRANSITION REGION TREATMENT! 
+      if(pos_neg < 0){ towerID_Modifier = 300000; } 
+      else if(pos_neg > 0){ towerID_Modifier = 400000; }
+    }
+    else {
+      if( (eta_index / 4) < 15 ){ 
+	if(pos_neg < 0){ towerID_Modifier = 300000; }
+	else if(pos_neg > 0){ towerID_Modifier = 400000; }
+      }
+      else{
+	if(pos_neg < 0){ towerID_Modifier = 500000; }
+	else if(pos_neg > 0){ towerID_Modifier = 600000; }
+      }
+    }
+
+    break;
+  }
+  case CaloSampling::EME3: {
+    
+    // Layer 3 of the EM End-Cap.  Supercells are 0.1 x 0.1 unless stated otherwise.
+    // Region 0 does not exist.
+    // Region 1 has 3 supercells in 1.5 < eta < 1.8, and 64 supercells in phi.  Supercells are 0.1 x 0.1.
+    // Region 2 has 2 supercells in 1.8 < eta < 2.0, and 64 supercells in phi.  Supercells are 0.1 x 0.1.
+    // Region 3 has 4 supercells in 2.0 < eta < 2.4, and 64 supercells in phi.  Supercells are 0.1 x 0.1.
+    // Region 4 has 1 supercells in 2.4 < eta < 2.5, and 64 supercells in phi.  Supercells are 0.1 x 0.1.
+    // No other Regions exist
+    
+    layer = 3; // By definition
+    
+    switch (region) {
+    case 0: {
+
+      towereta = eta_index;
+      towerphi = phi_index;
+      
+      iCell = 9; // By definition
+      
+      break;
+    }
+    default: {
+      ATH_MSG_DEBUG("CaloSampling::EME3 -> invalid 'region' value: " << region << " (Under investigation) ");
+      break;
+    }
+      break;
+    }
+    
+    if(pos_neg < 0){ towerID_Modifier = 500000; }
+    else if(pos_neg > 0){ towerID_Modifier = 600000; }
+
+    break;
+  }
+    // Hadronic End-cap (HEC)
+  case CaloSampling::HEC0:
+  case CaloSampling::HEC1:
+  case CaloSampling::HEC2:
+  case CaloSampling::HEC3: {
+    
+    // All Layers of the Hadronic End-Cap.
+    // Region 0 has 10 supercells in 1.5 < eta < 2.5, and 32 supercells in phi.  Supercells are 0.1 x 0.1.
+    // Region 1 has 4 supercells in 2.5 < eta < 3.3, and 16 supercells in phi.  Supercells are 0.2 x 0.2.
+    
+    switch(region){
+    case 0: {
+
+      towereta = eta_index;
+      towerphi = phi_index;
+      
+      layer = 4; // By definition
+      
+      switch (sample){ // only one supercell per layer in all regions for HECX
+      case CaloSampling::HEC0: { iCell = 10; break; }
+      case CaloSampling::HEC1: { iCell = 11; break; }
+      case CaloSampling::HEC2: { iCell = 12; break; }
+      case CaloSampling::HEC3: { iCell = 13; break; }
+      default: {
+	ATH_MSG_DEBUG("CaloSampling::HECX -> invalid sample for assigning iCell value! " << sample << " (Under investigation) ");
+	break;
+      }
+      }
+      break;
+      
+    }
+    case 1: {
+      validcell = false; // any region 1 HEC cells are actually with eta > 2.5
+      //ATH_MSG_DEBUG("CaloSampling::HECX Region 1 invalid as outside of eta range!");
+      break;
+    }
+    default: { break; }
+    }
+    
+    // Tower connection
+    if(pos_neg < 0){ towerID_Modifier = 500000; }
+    else if(pos_neg > 0){ towerID_Modifier = 600000; }
+    
+    break;
+  }
+  case CaloSampling::TileBar0:
+  case CaloSampling::TileBar1:
+  case CaloSampling::TileBar2: {
+    REPORT_MESSAGE_WITH_CONTEXT (MSG::DEBUG, "eSuperCellTowerMapper") << "Supercell is from Tile Barrel - it will be ignored.";
+    validcell = false;
+    //ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercell is from Tile Barrel - it will be ignored.");
+    break;
+  }
+  case CaloSampling::TileGap1:
+  case CaloSampling::TileGap2:
+  case CaloSampling::TileGap3: {
+    //ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercell is from Tile Gap (ITC and scintillator) - it will be ignored.");
+    validcell = false;
+    break;
+  }
+  case CaloSampling::TileExt0:
+  case CaloSampling::TileExt1:
+  case CaloSampling::TileExt2: {
+    //ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercell is from Tile Extended Barrel - it will be ignored.");
+    validcell = false;
+    break;
+  }
+  case CaloSampling::FCAL0:
+  case CaloSampling::FCAL1:
+  case CaloSampling::FCAL2: {
+    //ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercell is from Forward EM endcap - it will be ignored.");
+    validcell = false;
+    break;
+  }
+  case CaloSampling::MINIFCAL0:
+  case CaloSampling::MINIFCAL1:
+  case CaloSampling::MINIFCAL2:
+  case CaloSampling::MINIFCAL3: {
+    //ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercells is from MiniFCAL - it will be ignored.");
+    validcell = false;
+    break;
+  }
+  case CaloSampling::Unknown: {
+    //ATH_MSG_WARNING("\n==== eSuperCellTowerMapper ============ Supercell sampling is officially unknown - it will be ignored. (Needs investigation).  Please report this!");
+    validcell = false;
+    break;
+  }
+  default: {
+    ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercell has invalid CaloSampling value: " << sample << " (Needs investigation).  Please report this!");
+    validcell = false;
+    break;
+  }
+  }
+
+  if(validcell){
+    iETower = FindTowerIDForSuperCell(towereta, towerphi) + towerID_Modifier;
+    if(doPrint){
+      PrintCellSpec(sample, layer, region, eta_index, phi_index, pos_neg, iETower, iCell, prov, ID, doenergysplit);
+    }
+    ConnectSuperCellToTower( my_eTowerContainerRaw, iETower, ID, iCell, et, layer, doenergysplit);
+  }
+
+  // END ITERATING OVER SUPER CELLS+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++
+  
+  return 1;
+  
+  }
+
+int eSuperCellTowerMapper::FindTowerIDForSuperCell(int towereta, int towerphi)
+{
+
+  return (towerphi + (64 * towereta));
+
+}
+
+  void eSuperCellTowerMapper::PrintCellSpec(const CaloSampling::CaloSample sample, int layer, const int region, const int eta_index, const int phi_index, const int pos_neg, int iETower, int iCell, int prov, Identifier ID ,bool doenergysplit)
+{
+  
+  std::string sampleName = "";
+  
+  switch (sample) {
+  case CaloSampling::PreSamplerB: { sampleName = "PreSamplerB"; break; }
+  case CaloSampling::EMB1: { sampleName = "EMB1"; break; }
+  case CaloSampling::EMB2: { sampleName = "EMB2"; break; }
+  case CaloSampling::EMB3: { sampleName = "EMB3"; break; }
+  case CaloSampling::PreSamplerE: { sampleName = "PreSamplerE"; break; }
+  case CaloSampling::EME1: { sampleName = "EME1"; break; }
+  case CaloSampling::EME2: { sampleName = "EME2"; break; }
+  case CaloSampling::EME3: { sampleName = "EME3"; break; }
+  case CaloSampling::HEC0: { sampleName = "HEC0"; break; }
+  case CaloSampling::HEC1: { sampleName = "HEC1"; break; }
+  case CaloSampling::HEC2: { sampleName = "HEC2"; break; }
+  case CaloSampling::HEC3: { sampleName = "HEC3"; break; }
+  default: {
+    ATH_MSG_DEBUG("\n==== eSuperCellTowerMapper ============ Supercell has invalid CaloSampling value: " << sample << " (Needs investigation).  Please report this!");
+    break;
+  }
+  }
+  
+  if(true){
+    ATH_MSG_DEBUG("ASSIGNED CELL:::  CASE: " << sampleName
+	      << "\tSample: " << sample
+	      << "\tLayer: " << layer
+	      << "\tRegion: " << region
+	      << "\tEta_Index: " << eta_index
+	      << "\tPhi_Index: " << phi_index
+	      << "\tPosNeg: " << pos_neg
+	      << "\tiETower: " << iETower
+	      << "\tiCell: " << iCell
+	      << "\tDoEnergySplit: " << doenergysplit
+	      << "\tProvenance: " << prov
+	      << "\tID: " << ID
+		  << " ");
+  }
+
+  return;
+}
+
+
+} // end of LVL1 namespace
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTower.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTower.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f104b748ff06fd0c0d24f069f16188afbd6696b6
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTower.cxx
@@ -0,0 +1,364 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eTower.h  -  description
+//                              -------------------
+//     begin                : 19 02 2019
+//     email                : Alan.Watson@cern.ch, jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eFEXCompression.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include <cmath>
+
+
+namespace LVL1 {
+
+  const int s_cells[] = {1,4,4,1,4};
+  const int s_offsets[] = {0,1,5,9,10};
+  
+  // default constructor
+  eTower::eTower():
+    m_eta(0.),
+    m_phi(0.),
+    m_tower_id(-9999999),
+    m_posneg(0)
+  {
+    this->clear_scIDs();
+    this->clearET();
+  }
+  
+  /** constructs a tower and sets the coordinates and identifier */
+  eTower::eTower(float eta, float phi, int id_modifier, int posneg):
+    m_eta(eta),
+    m_phi(phi),
+    m_tower_id(id_modifier + phi + (64 * eta)),
+    m_posneg(posneg)
+  {
+    this->clear_scIDs();
+    this->clearET();
+  }
+  
+  /** Destructor */
+  eTower::~eTower(){
+  }
+  
+  /** Clear and resize ET value vector */
+  void eTower::clearET()
+  {
+    m_et.clear();
+    m_et.resize(14);
+    m_et_float.clear();
+    m_et_float.resize(14);
+    for (unsigned int i=0; i<m_et.size(); i++){
+      m_et[i] = 0;
+      m_et_float[i] = 0.0;
+    }
+  }
+
+  /** Clear and resize Identifier value vector */
+  void eTower::clear_scIDs()
+  {
+    m_scID.clear();
+    m_scID.resize(14);
+    for (unsigned int i=0; i<m_scID.size(); i++){
+      m_scID[i] = Identifier();
+    }
+  }
+
+
+  void eTower::setPosNeg(int posneg){
+    
+    m_posneg = posneg;
+
+    return;
+
+  }
+
+  /** Add ET to a specified cell */
+  void eTower::addET(float et, int cell)
+  {
+    /// Check cell index in range for layer - should probably throw a warning...
+    if (cell < 0  || cell > 13){ return; }
+    
+    m_et_float[cell] += et;
+
+    return;
+
+  }
+  void eTower::setET(int cell, float et, int layer) {
+    /// Check cell index in range for layer
+    if (cell < 0  || cell > 13){ return; }
+      
+    addET(et, cell);
+    
+    //multi linear digitisation encoding
+    unsigned int ecode = eFEXCompression::Compress(m_et_float[cell]);
+    int outET = eFEXCompression::Expand(ecode);
+    
+    //noise cut
+    bool SCpass = noiseCut(outET,layer);
+    if (SCpass){ m_et[cell] = outET;}
+    else{ m_et[cell] = 0; }
+  }
+
+  /** Set supercell position ID and ET**/
+  void eTower::setSCID(Identifier ID, int cell, float et, int layer, bool doenergysplit)
+  {
+    
+    /// Check cell index in range for layer
+    if (cell < 0  || cell > 13){ return; }
+
+    if(!doenergysplit){
+      
+      addET(et, cell);
+      
+      m_scID[cell] = ID;
+      
+      //multi linear digitisation encoding
+      unsigned int ecode = eFEXCompression::Compress(m_et_float[cell]);
+      int outET = eFEXCompression::Expand(ecode);
+      
+      //noise cut
+      bool SCpass = noiseCut(outET,layer);
+      if (SCpass){ m_et[cell] = outET;}
+      else{ m_et[cell] = 0; }
+      
+    }
+    else{
+
+      float et1 = et/2;
+      float et2 = et/2;
+      addET(et1, cell);
+      addET(et2, cell+1);
+
+      unsigned int ecode1 = eFEXCompression::Compress(m_et_float[cell]);
+      int outET1 = eFEXCompression::Expand(ecode1);
+      unsigned int ecode2 = eFEXCompression::Compress(m_et_float[cell+1]);
+      int outET2 = eFEXCompression::Expand(ecode2);
+
+      //noise cuts
+      bool SCpass1 = noiseCut(outET1,layer);
+      if (SCpass1){ m_et[cell] = outET1;}
+      else{ m_et[cell] = 0; }
+      bool SCpass2 = noiseCut(outET2,layer);
+      if (SCpass2){ m_et[cell+1] = outET2;}
+      else{ m_et[cell+1] = 0; }
+
+    }
+
+    return;
+
+  }
+
+  /** Apply noise cut per layer **/
+  bool eTower::noiseCut(int et, int layer)
+  {
+
+    bool pass=true;                                                                                                         
+    if(layer==0) {
+      if(et<m_noisecutPS){ pass = false; }
+    } 
+    else if (layer==1) {
+      if(et<m_noisecutL1){ pass = false; }
+    } 
+    else if (layer==2) {
+      if(et<m_noisecutL2){ pass = false; }
+    } 
+    else if (layer==3) {
+      if(et<m_noisecutL3){ pass = false; }
+    } 
+    else if (layer==4) {
+      if(et<m_noisecutHad){ pass = false; }
+    } 
+    else { pass = false; }
+    
+    return pass;
+
+  }
+
+  /** Return global eta index.
+      Should be derived from tower ID, should be corrected in the future.
+      Need to also think what index range should be (thinking ahead to Run2) */
+  int eTower::iEta() {
+    int index = (m_eta + 2.5)/0.1;
+    return index;
+  }
+  
+  /** Return global phi index.
+      Should be derived from tower ID, should be corrected in the future.
+      Decision here is whether phi is signed or not */
+  int eTower::iPhi() {
+    int index = 32*m_phi/M_PI;
+    if (m_phi < 0) index = 32*(m_phi + 2*M_PI)/M_PI;
+    return index;
+  }
+  
+  /** Return ET of specified supercell */
+  int eTower::getET(unsigned int layer,  int cell) const {
+    
+    /// Check cell index in range for layer
+    if (layer > 5 || cell < 0 || cell >= s_cells[layer]) return 0;
+    
+    // Return ET
+    return m_et[s_offsets[layer] + cell];
+    
+  }
+
+  /** Return ET of specified supercell FLOAT VERSION */
+  float eTower::getET_float(unsigned int layer, int cell) const {
+
+    /// Check cell index in range for layer
+    if (layer > 5 || cell < 0 || cell >= s_cells[layer]) return 0;
+
+    // Return ET
+    return m_et_float[s_offsets[layer] + cell];
+
+  }
+
+  /** Return ET of all supercells together*/
+  int eTower::getTotalET() const{
+    
+    int tmp = 0;
+    for (unsigned int i=0; i<m_et.size(); i++){
+      tmp += m_et[i];
+    }
+
+    return tmp;
+    
+  }
+
+  /** Return ET of all supercells together FLOAT VERSION */
+  float eTower::getTotalET_float() const{
+
+    float tmp = 0;
+    for (unsigned int i=0; i<m_et_float.size(); i++){
+      tmp += m_et_float[i];
+    }
+
+    return tmp;
+
+  }
+
+  
+  /** Return supercell ET values for specified layer */
+  std::vector<int> eTower::getLayerETvec(unsigned int layer) const {
+    
+    /// Create empty vector of data
+    std::vector<int> cells;
+    
+    /// Check cell index in range for layer
+    if (layer > 5) return cells;
+    
+    /// Fill output vector
+    for (int cell = 0; cell < s_cells[layer]; ++cell) cells.push_back(m_et[s_offsets[layer] + cell]);
+    
+    return cells;
+  }
+
+
+  /** Return supercell ET values for specified layer FLOAT VERSION */
+  std::vector<float> eTower::getLayerETvec_float(unsigned int layer) const {
+
+    /// Create empty vector of data
+    std::vector<float> cells;
+
+    /// Check cell index in range for layer
+    if (layer > 5) return cells;
+
+    /// Fill output vector
+    for (int cell = 0; cell < s_cells[layer]; ++cell) cells.push_back(m_et_float[s_offsets[layer] + cell]);
+
+    return cells;
+  }
+
+
+  /** Return supercell ET values for specified layer */
+  int eTower::getLayerTotalET(unsigned int layer) const {
+        
+    if (layer == 0){
+      return m_et[0];
+    }
+    else if (layer == 1){
+      return (m_et[1] + m_et[2] + m_et[3] + m_et[4]);
+    }
+    else if (layer == 2){
+      return (m_et[5] + m_et[6] + m_et[7] + m_et[8]);
+    }
+    else if (layer == 3){
+      return m_et[9];
+    }
+    else if (layer == 4){
+      return (m_et[10] + m_et[11] + m_et[12] + m_et[13]);
+    }
+
+    
+    return 0;
+    
+  }
+
+  /** Return supercell ET values for specified layer FLOAT VERSION */
+  float eTower::getLayerTotalET_float(unsigned int layer) const {
+
+    if (layer == 0){
+      return m_et_float[0];
+    }
+    else if (layer == 1){
+      return (m_et_float[1] + m_et_float[2] + m_et_float[3] + m_et_float[4]);
+    }
+    else if (layer == 2){
+      return (m_et_float[5] + m_et_float[6] + m_et_float[7] + m_et_float[8]);
+    }
+    else if (layer == 3){
+      return m_et_float[9];
+    }
+    else if (layer == 4){
+      return (m_et_float[10] + m_et_float[11] + m_et_float[12] + m_et_float[13]);
+    }
+
+
+    return 0;
+
+  }
+
+  std::vector<Identifier> eTower::getLayerSCIDs(unsigned int layer) const{
+
+    std::vector<Identifier> cells_in_layer;
+    
+    if (layer == 0){
+      cells_in_layer.push_back(m_scID[0]);
+    }
+    else if (layer == 1){
+      cells_in_layer.push_back(m_scID[1]);
+      cells_in_layer.push_back(m_scID[2]);
+      cells_in_layer.push_back(m_scID[3]);
+      cells_in_layer.push_back(m_scID[4]);
+    }
+    else if (layer == 2){
+      cells_in_layer.push_back(m_scID[5]);
+      cells_in_layer.push_back(m_scID[6]);
+      cells_in_layer.push_back(m_scID[7]);
+      cells_in_layer.push_back(m_scID[8]);
+    }
+    else if (layer == 3){
+      cells_in_layer.push_back(m_scID[9]);
+    }
+    else if (layer == 4){
+      cells_in_layer.push_back(m_scID[10]);
+      cells_in_layer.push_back(m_scID[11]);
+      cells_in_layer.push_back(m_scID[12]);
+      cells_in_layer.push_back(m_scID[13]);
+    }
+
+    return cells_in_layer;
+
+  }
+
+  
+} // end of namespace bracket
+
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTowerBuilder.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTowerBuilder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..473d387d8a1580e2ce3a56235ddcc817838264cb
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTowerBuilder.cxx
@@ -0,0 +1,196 @@
+/*
+    Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+#include "xAODTrigL1Calo/TriggerTowerContainer.h"
+
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerBuilder.h"
+
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+#include "TROOT.h"
+#include "TH1.h"
+#include "TH1F.h"
+#include "TPad.h"
+#include "TCanvas.h"
+
+// TOWER IS A COLLECTION OF SUPER CELLS
+// IT SHOULD HAVE A UNIQUE ID
+// IT SHOULD BE ABLE TO RETURN LIST OF SUPER CELLS BELONGING TO IT
+
+// THIS IS A CLASS DESIGNED TO BUILD AN ETOWER USING THE ETOWER CLASS AND THEN PRINT THE RELEVANT INFORMATION TO THE SCREEN USING FUNCTION CALLS FROM THE ETOWER CLASS
+
+namespace LVL1 {
+
+eTowerBuilder::eTowerBuilder(const std::string& type,const std::string& name,const IInterface* parent):
+    AthAlgTool(type,name,parent)
+{
+  declareInterface<IeTowerBuilder>(this);
+}
+
+eTowerBuilder::~eTowerBuilder()
+{
+}
+
+
+void eTowerBuilder::init(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+
+  execute(eTowerContainerRaw);
+  return;
+}
+
+
+void eTowerBuilder::reset() 
+{
+  return;
+}
+
+
+void eTowerBuilder::execute(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+  BuildAllTowers(eTowerContainerRaw);
+  return;
+}
+ 
+  // TOWER IDs FOR CLARITY
+  // Left Barrel IETower = 100000 + X
+  // Right Barrel IETower = 200000 + X
+  // Left Transition ID Tower = 300000 + X;
+  // Right Transition ID Tower = 400000 + X;
+  // Left Endcap ID Tower = 500000 + X
+  // Right Endcap ID Tower = 600000 + X
+  // Left Hadronic Endcap ID Tower = 11100000 + X --> These are just Layer 5 of Endcap Towers.  They will never be generated as standalone eTowers.
+  // Right Haronic Endcap ID Tower = 22200000 + X --> These are just Layer 5 of Endcap Towers.  They will never be generated as standalone eTowers.
+
+ void eTowerBuilder::BuildEMBeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+  // Regions 0 only.  Region 1 is 'transition region'.
+  for (int ieta = 0; ieta < 14; ++ieta) { // loop over 14 eta steps (ignoring last step as it is transition region)
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 100000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 200000, 1);
+    }
+  }
+
+  return;
+}
+
+void eTowerBuilder::BuildTRANSeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+
+  int TRANS_MODIFIER = 14;
+  int tmpVal = TRANS_MODIFIER;
+
+  for (int ieta = tmpVal; ieta < tmpVal + 1; ieta++){ // loop over eta steps
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 300000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 400000, 1);
+    }
+  }
+
+  return;
+}
+
+  void eTowerBuilder::BuildEMEeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+  // Region 1
+  int EME_MODIFIER = 15;
+  int tmpVal = EME_MODIFIER;
+
+  for (int ieta = tmpVal; ieta < tmpVal + 3; ++ieta){ // loop over eta steps
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 500000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 600000, 1);
+    }
+    EME_MODIFIER++;
+  }
+
+  // Region 2
+  tmpVal = EME_MODIFIER;
+  for (int ieta = tmpVal; ieta < tmpVal + 2; ++ieta){ // loop over eta steps
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 500000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 600000, 1);
+    }
+    EME_MODIFIER++;
+  }
+
+  // Region 3
+  tmpVal = EME_MODIFIER;
+  for (int ieta = tmpVal; ieta < tmpVal + 4; ++ieta){ // loop over eta steps
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 500000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 600000, 1);
+    }
+    EME_MODIFIER++;
+  }
+
+  // Region 4
+  tmpVal = EME_MODIFIER;
+  for (int ieta = tmpVal; ieta < tmpVal + 1; ++ieta){ // loop over eta steps
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 500000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 600000, 1);
+    }
+    EME_MODIFIER++;
+  }
+
+  return;
+
+}
+
+// REDUNDANT AND NOT USED==========================================================================================================
+  void eTowerBuilder::BuildHECeTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+
+  // Region 0
+  int HEC_MODIFIER = 29;
+  int tmpVal = HEC_MODIFIER;
+  for (int ieta = tmpVal; ieta < tmpVal + 10; ++ieta){ // loop over eta steps
+    for (int iphi = 0; iphi < 64; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 11100000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 22200000, 1);
+    }
+    HEC_MODIFIER++;
+  }
+
+  // Region 1
+  tmpVal = HEC_MODIFIER;
+  for (int ieta = tmpVal; ieta < tmpVal + 4; ++ieta){ // loop over eta steps
+    for (int iphi = 0; iphi < 32; ++iphi){ // loop over 64 phi steps
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 11100000, -1);
+      BuildSingleTower(eTowerContainerRaw, ieta, iphi, 22200000, 1);
+    }
+    HEC_MODIFIER++;
+  }
+
+  return;
+
+}
+
+void eTowerBuilder::BuildSingleTower(std::unique_ptr<eTowerContainer> & eTowerContainerRaw,float eta, float phi, float keybase, int posneg) 
+{
+
+  eTowerContainerRaw->push_back(eta, phi, keybase, posneg);
+
+  return;
+
+}
+
+void eTowerBuilder::BuildAllTowers(std::unique_ptr<eTowerContainer> & eTowerContainerRaw) 
+{
+  BuildEMBeTowers(eTowerContainerRaw);
+  BuildTRANSeTowers(eTowerContainerRaw);
+  BuildEMEeTowers(eTowerContainerRaw);
+  return;
+
+}
+
+} // end of LVL1 namespace
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTowerContainer.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTowerContainer.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9d7cd000f3f8a58f4ba2a32119f7082d2913e30d
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eTowerContainer.cxx
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Code stolen shamelessly from Calorimeter/CaloEvent/src/CaloCellContainer.cxx and modified
+
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "AthenaKernel/errorcheck.h"
+#include "CLHEP/Geometry/Vector3D.h"
+#include <boost/algorithm/cxx11/partition_point.hpp>
+#include <atomic>
+
+namespace LVL1{
+
+eTowerContainer::eTowerContainer(SG::OwnershipPolicy ownPolicy) : 
+  DataVector<LVL1::eTower>(ownPolicy)
+{ 
+  m_map_towerID_containerIndex.clear();
+}
+
+void eTowerContainer::push_back(float eta, float phi, float keybase, int posneg)
+{
+  DataVector<LVL1::eTower>::push_back(std::make_unique<eTower>(eta,phi,keybase,posneg));
+}
+
+void eTowerContainer::print() const {
+  REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING, "eTowerContainer") << "eTowerContainer::print not implemented";
+}
+
+
+const LVL1::eTower * eTowerContainer::findTower(int towerID) const
+{
+  int container_index = -1;
+  container_index = m_map_towerID_containerIndex.find(towerID)->second;
+  if(container_index >= 0){
+    return (*this)[container_index];
+  }
+  return 0;
+}
+
+LVL1::eTower * eTowerContainer::findTower(int towerID)
+{
+  int container_index = -1;
+  container_index = m_map_towerID_containerIndex.find(towerID)->second;
+  if(container_index >= 0){
+    return (*this)[container_index];
+  }
+  return 0;
+}
+
+void eTowerContainer::clearContainerMap()
+{
+  m_map_towerID_containerIndex.clear();
+}
+
+bool eTowerContainer::fillContainerMap(){
+  clearContainerMap();
+  size_t ntowers = size();
+  for (size_t itower = 0; itower < ntowers; itower++) {
+    const eTower * theTower = (*this)[itower];
+    int towerID = theTower->constid();
+    int container_index = itower;
+    m_map_towerID_containerIndex.insert(std::pair<int,int>(towerID,container_index));
+  }
+  return true;
+}
+
+}
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/CMakeLists.txt b/Trigger/TrigT1/L1CaloFEXToolInterfaces/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a4e134a7c8d4cce0ac9ce851c01de67da31489a7
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/CMakeLists.txt
@@ -0,0 +1,16 @@
+################################################################################
+# Package: L1CaloFEXToolInterfaces
+################################################################################
+
+# Declare the package name:
+atlas_subdir( L1CaloFEXToolInterfaces )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs( PUBLIC
+                          Control/AthenaBaseComps 
+			  GaudiKernal
+			  )
+
+atlas_add_library( L1CaloFEXToolInterfaces
+                   PUBLIC_HEADERS L1CaloFEXToolInterfaces
+                   LINK_LIBRARIES AthenaBaseComps CaloEvent xAODTrigL1Calo CaloIdentifier )#GaudiKernal )
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXFPGA.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXFPGA.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8ee1663a1a489b860b214292b925c7c20d340cc
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXFPGA.h
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXFPGA.h  -
+//                              -------------------
+//     begin                : 23 03 2019
+//     email                :  jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeFEXFPGA_H
+#define IeFEXFPGA_H
+
+
+#include "GaudiKernel/IAlgTool.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eFEXFPGA
+*/
+
+  static const InterfaceID IID_IeFEXFPGA("LVL1::IeFEXFPGA", 1, 0);
+
+  class IeFEXFPGA : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+
+    virtual StatusCode init(int id, int efexid) = 0;
+
+    virtual StatusCode execute() = 0;
+
+    virtual void reset() = 0;
+
+    virtual int ID() = 0;
+
+    virtual void SetTowersAndCells_SG(int [][6]) = 0;
+
+  private:
+
+  };
+
+  inline const InterfaceID& LVL1::IeFEXFPGA::interfaceID()
+  {
+    return IID_IeFEXFPGA;
+  }
+
+} // end of namespace
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXSim.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXSim.h
new file mode 100644
index 0000000000000000000000000000000000000000..8bf6935dcd66f707c82991e91fbad03e7bafd09b
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXSim.h
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXSim.h  -
+//                              -------------------
+//     begin                : 23 03 2019
+//     email                :  jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeFEXSim_H
+#define IeFEXSim_H
+
+#include "GaudiKernel/IAlgTool.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloEvent/CaloCellContainer.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eFEXSim
+*/
+
+  static const InterfaceID IID_IeFEXSim("LVL1::IeFEXSim", 1, 0);
+
+  class IeFEXSim : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+
+    virtual void init(int id) = 0;
+
+    virtual void reset() = 0;
+
+    virtual void execute() = 0;
+    virtual int ID() = 0;
+    virtual void SetTowersAndCells_SG(int tmp[10][18]) = 0;
+
+    virtual StatusCode NewExecute(int tmp[10][18]) = 0;
+
+  private:
+
+  };
+
+  inline const InterfaceID& LVL1::IeFEXSim::interfaceID()
+  {
+    return IID_IeFEXSim;
+  }
+
+} // end of namespace
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXSysSim.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXSysSim.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c99ad230ff5f11315f3478f9958c0e9797a5e52
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXSysSim.h
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           eFEXSysSim.h  -
+//                              -------------------
+//     begin                : 23 03 2019
+//     email                :  jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeFEXSysSim_H
+#define IeFEXSysSim_H
+
+#include "GaudiKernel/IAlgTool.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloEvent/CaloCellContainer.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eFEXSysSim
+*/
+
+  static const InterfaceID IID_IeFEXSysSim("LVL1::IeFEXSysSim", 1, 0);
+
+  class IeFEXSysSim : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+    
+    virtual StatusCode execute() = 0;
+
+    virtual void init() = 0;
+
+    virtual void cleanup() = 0;
+
+    virtual int calcTowerID(int eta, int phi, int mod) = 0 ;
+    
+  private:
+
+  };
+
+  inline const InterfaceID& LVL1::IeFEXSysSim::interfaceID()
+  {
+    return IID_IeFEXSysSim;
+  }
+
+} // end of namespace
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXegAlgo.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXegAlgo.h
new file mode 100644
index 0000000000000000000000000000000000000000..4df595db7d02103c054e4878754acd465e2cd2ae
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXegAlgo.h
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           IeFEXegAlgo.h  -
+//                              -------------------
+//     begin                : 19 06 2020
+//     email                :  nicholas.andrew.luongo@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeFEXegAlgo_H
+#define IeFEXegAlgo_H
+
+#include "GaudiKernel/IAlgTool.h"
+#include "L1CaloFEXSim/eFEXegTOB.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eFEXegAlgo
+*/
+
+  static const InterfaceID IID_IeFEXegAlgo("LVL1::IeFEXegAlgo", 1, 0);
+
+  class IeFEXegAlgo : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+
+    virtual StatusCode safetyTest() = 0;
+    virtual void setup(int inputTable[3][3]) = 0;
+
+    virtual std::vector<unsigned int> getReta() = 0;
+    virtual void getRhad(std::vector<unsigned int> & ) = 0;
+    virtual void getWstot(std::vector<unsigned int> & ) = 0;
+    virtual void getRealPhi(float & phi) = 0;
+    virtual void getRealEta(float & eta) = 0;
+    virtual std::unique_ptr<eFEXegTOB> geteFEXegTOB() = 0;
+    virtual unsigned int getET() = 0;
+    virtual void getWindowET(int layer, int jPhi, int SCID, unsigned int &) = 0;
+    virtual bool haveSeed() = 0;
+    virtual void getCoreEMTowerET(unsigned int & et) = 0;
+    virtual void getCoreHADTowerET(unsigned int & et) = 0;
+
+  private:
+    virtual void setSeed() = 0;
+
+  };
+
+  inline const InterfaceID& LVL1::IeFEXegAlgo::interfaceID()
+  {
+    return IID_IeFEXegAlgo;
+  }
+
+} // end of namespace
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h
new file mode 100644
index 0000000000000000000000000000000000000000..c85e39d0b3e8b6e6a5e1302fe6d1972d06f09040
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           IeFEXtauAlgo.h  -
+//                              -------------------
+//     begin                : 12 05 2020
+//     email                :  nicholas.andrew.luongo@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeFEXtauAlgo_H
+#define IeFEXtauAlgo_H
+
+#include "GaudiKernel/IAlgTool.h"
+#include "L1CaloFEXSim/eFEXtauTOB.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eFEXtauAlgo
+*/
+
+  static const InterfaceID IID_IeFEXtauAlgo("LVL1::IeFEXtauAlgo", 1, 0);
+
+  class IeFEXtauAlgo : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+
+    virtual StatusCode safetyTest() = 0;
+    virtual void setup(int inputTable[3][3]) = 0;
+    
+    virtual bool isCentralTowerSeed() = 0;
+    virtual eFEXtauTOB* getTauTOB() = 0;
+    virtual float getIso() = 0;
+    virtual unsigned int getEt() = 0;
+    virtual unsigned int getBitwiseEt() = 0;
+
+  private:
+
+  };
+
+  inline const InterfaceID& LVL1::IeFEXtauAlgo::interfaceID()
+  {
+    return IID_IeFEXtauAlgo;
+  }
+
+} // end of namespace
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeSuperCellTowerMapper.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeSuperCellTowerMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..f21e9141df814256fc1ae6140ef341a02e2888ed
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeSuperCellTowerMapper.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           IeSuperCellTowerMapper.h  -
+//                              -------------------
+//     begin                : 23 03 2019
+//     email                :  jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeSuperCellTowerMapper_H
+#define IeSuperCellTowerMapper_H
+
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "CaloIdentifier/CaloCell_SuperCell_ID.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+#include "xAODTrigL1Calo/TriggerTowerContainer.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eSuperCellTowerMapper
+*/
+
+  static const InterfaceID IID_IeSuperCellTowerMapper("LVL1::IeSuperCellTowerMapper", 1, 0);
+
+  class IeSuperCellTowerMapper : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+
+    virtual StatusCode AssignSuperCellsToTowers(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw) = 0;
+    virtual StatusCode AssignTriggerTowerMapper(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw) = 0;
+    
+    virtual void reset() = 0;
+    
+    virtual int FindAndConnectTower(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw,CaloSampling::CaloSample sample,const int region, int layer, const int pos_neg, const int eta_index, const int phi_index, Identifier ID, float et, int prov, bool doPrint) = 0;
+    virtual int ConnectSuperCellToTower(/*eTowerContainer**/std::unique_ptr<eTowerContainer> & my_eTowerContainerRaw, int iETower, Identifier ID, int iCell, float et, int layer, bool doenergysplit) = 0;
+    virtual int FindTowerIDForSuperCell(int towereta, int towerphi) = 0;
+    virtual void PrintCellSpec(const CaloSampling::CaloSample sample, int layer, const int region, const int eta_index, const int phi_index, const int pos_neg, int iETower, int iCell, int prov, Identifier ID, bool doenergysplit) = 0;
+
+  private:
+
+  };
+
+  inline const InterfaceID& LVL1::IeSuperCellTowerMapper::interfaceID()
+  {
+    return IID_IeSuperCellTowerMapper;
+  }
+
+} // end of namespace
+
+#endif
diff --git a/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeTowerBuilder.h b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeTowerBuilder.h
new file mode 100644
index 0000000000000000000000000000000000000000..1416a55ffc8a558f6671ce0ddb7242a220bf4361
--- /dev/null
+++ b/Trigger/TrigT1/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeTowerBuilder.h
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+//***************************************************************************
+//                           IeTowerBuilder.h  -
+//                              -------------------
+//     begin                : 23 03 2019
+//     email                :  jacob.julian.kempster@cern.ch
+//  ***************************************************************************/
+
+#ifndef IeTowerBuilder_H
+#define IeTowerBuilder_H
+
+#include "GaudiKernel/IAlgTool.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "L1CaloFEXSim/eTower.h"
+#include "L1CaloFEXSim/eTowerContainer.h"
+
+namespace LVL1 {
+  
+/*
+Interface definition for eTowerBuilder
+*/
+
+  static const InterfaceID IID_IeTowerBuilder("LVL1::IeTowerBuilder", 1, 0);
+
+  class IeTowerBuilder : virtual public IAlgTool {
+  public:
+    static const InterfaceID& interfaceID( ) ;
+
+    virtual void BuildEMBeTowers(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0;
+    virtual void BuildTRANSeTowers(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0;
+    virtual void BuildEMEeTowers(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0 ;
+    virtual void BuildHECeTowers(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0;
+    virtual void BuildAllTowers(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0;
+    virtual void BuildSingleTower(std::unique_ptr<eTowerContainer> & eTowerContainer,float eta, float phi, float keybase, int posneg) = 0;
+    
+    virtual void init(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0;
+    virtual void execute(std::unique_ptr<eTowerContainer> & eTowerContainer) = 0;
+    virtual void reset() = 0;
+
+
+  private:
+
+  };
+
+  inline const InterfaceID& LVL1::IeTowerBuilder::interfaceID()
+  {
+    return IID_IeTowerBuilder;
+  }
+
+} // end of namespace
+
+#endif