diff --git a/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/FPGATrackSimBinStep.h b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/FPGATrackSimBinStep.h
new file mode 100644
index 0000000000000000000000000000000000000000..b92b0a8339621f37c9786bc40db4ae1baee60d5e
--- /dev/null
+++ b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/FPGATrackSimBinStep.h
@@ -0,0 +1,125 @@
+// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
+
+#ifndef FPGATrackSimBinStep_H
+#define FPGATrackSimBinStep_H
+
+/**
+ * @file FPGATrackSimBinStep.h
+ * @author Elliot Lipeles
+ * @date Sept 10th, 2024
+ * @brief Binning Classes for BinStep
+ *
+ * Declarations in this file (there are a series of small classes):
+ *      class FPGATrackSimBinStep
+ *      
+ * 
+ * Overview of stucture:
+ *    -- 
+ * 
+
+ * 
+ * References:
+ *
+ */
+#include "AthenaBaseComps/AthAlgTool.h"
+
+
+#include "FPGATrackSimBinning/FPGATrackSimBinArray.h"
+#include "FPGATrackSimBinning/FPGATrackSimBinUtil.h"
+#include "FPGATrackSimBinning/IFPGATrackSimBinDesc.h"
+
+#include "GaudiKernel/StatusCode.h"
+
+#include <cmath>
+#include <string>
+#include <vector>
+#include <array>
+
+// Use IdxSet and ParSet from FPGATrackSimUtil
+using FPGATrackSimBinUtil::ParSet;
+using FPGATrackSimBinUtil::IdxSet;
+
+class FPGATrackSimBinTool;
+
+//--------------------------------------------------------------------------------------------------
+//
+// Class to define the sub steps of the full binning
+//
+//--------------------------------------------------------------------------------------------------
+class FPGATrackSimBinStep : virtual public AthAlgTool {
+public:
+  FPGATrackSimBinStep(const std::string & algname, const std::string & name,
+                      const IInterface * ifc) : AthAlgTool(algname, name, ifc) {}
+
+  virtual StatusCode initialize() override;
+  StatusCode setRanges(const FPGATrackSimBinStep* prev,const ParSet& parMin, const ParSet& parMax);
+
+  // property of step
+  const std::vector<unsigned> stepIdx(IdxSet idx) const; // index for only the pars used in this step
+  const std::vector<unsigned> stepBins() const;   // bin sizes for only the pars used in this step
+  const std::vector<unsigned>& stepPars() const {return m_pars;}  // parameters used for this step
+  const std::vector<unsigned> nBins() const {return m_parBins;}   // bin sizes for only the pars used in this step
+  const std::string& stepName() const {return m_name;}
+  unsigned stepNum() const {return m_stepNum;}
+
+  // Calculation of bin boundaries
+  double binCenter(unsigned par, unsigned bin) const { return m_parMin[par] + m_parStep[par] * (double(bin) + 0.5); }
+  double binLowEdge(unsigned par, unsigned bin) const { return m_parMin[par] + m_parStep[par] * (double(bin)); }
+  double binHighEdge(unsigned par, unsigned bin) const { return m_parMin[par] + m_parStep[par] * (double(bin) + 1.0);}
+  double binWidth(unsigned par) const { return m_parStep[par]; }
+  ParSet binLowEdge(const IdxSet &idx) const;
+  ParSet binCenter(const IdxSet &idx) const;
+
+  // get bin value for a specific parameter value
+  unsigned binIdx(unsigned par, double val) const {
+    return (val > m_parMin[par]) ? unsigned(floor((val - m_parMin[par]) / m_parStep[par])): 0; }
+
+  // convert parset (the binning parameters) to a 5-d bin
+  IdxSet binIdx(const ParSet &pars) const;
+
+  // Convert to previous steps idx
+  IdxSet convertToPrev(const IdxSet& cur) const;  
+
+  //--------------------------------------------------------------------------------------------------
+  //
+  //  Set which bins are valid
+  //
+  //--------------------------------------------------------------------------------------------------
+  // Which bins are consistent with the (pT, eta, pho, d0, z0)
+  // ranges computed from region definition defined in the eventselection
+  // service or set by the layer map
+  void initValidBins();
+  void setValidBin(const std::vector<unsigned>& idx); // also sets SubBins
+  void printValidBin() const; // dump an output to log for x-checks
+  const FPGATrackSimBinArray<int>& validBinsFull() const { return m_validBinFull;}
+  const FPGATrackSimBinArray<int>& validBinsLocal() const { return m_validBinLocal;}
+
+private:
+  Gaudi::Property<std::string> m_name{this, "name", {}, "String name assigned to Binning Step"};
+  Gaudi::Property<std::vector<unsigned>> m_parBinsConfig{this,"parBins",{},"Vector of number of bins for each parameter (expect 5)"};
+
+  // pars used in this step
+  std::vector<unsigned> m_pars{}; 
+
+  // Array that has a true/false for if a bin is valid
+  // some bins may not be valid because they correspond to (pT,eta,phi,d0,z0)
+  // that are being targeted for reconstruction
+  FPGATrackSimBinArray<int> m_validBinFull; // this is the full binning
+  FPGATrackSimBinArray<int> m_validBinLocal; // this is for the pars used at this step
+
+  // pointer to FPGATrackSimBinStep of previous step
+  const FPGATrackSimBinStep *m_prev{0};
+  unsigned m_stepNum{}; // number of step
+  
+  // the bins for this step
+  ParSet m_parStep;
+  IdxSet m_parBins; // one means no binning this step
+
+  // reference to the full range defined in the "tool"
+  ParSet m_parMin;
+  ParSet m_parMax;
+  
+  friend FPGATrackSimBinTool;
+};
+
+#endif // FPGATrackSimBinStep_H
diff --git a/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/FPGATrackSimBinTool.h b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/FPGATrackSimBinTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..b344b03d76cacc9bb813beff1ec9e391b8efeca8
--- /dev/null
+++ b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/FPGATrackSimBinTool.h
@@ -0,0 +1,122 @@
+// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
+
+#ifndef FPGATrackSimBinTool_H
+#define FPGATrackSimBinTool_H
+
+/**
+ * @file FPGATrackSimBinTool.h
+ * @author Elliot Lipeles
+ * @date Sept 10th, 2024
+ * @brief Binning Classes for BinTool
+ *
+ * Declarations in this file (there are a series of small classes):
+ *      class FPGATrackSimBinTool
+ *      
+ * 
+ * Overview of stucture:
+ *    -- 
+ * 
+
+ * 
+ * References:
+ *
+ */
+#include "AthenaBaseComps/AthAlgTool.h"
+
+#include "FPGATrackSimConfTools/IFPGATrackSimEventSelectionSvc.h"
+
+#include "FPGATrackSimBinUtil.h"
+#include "IFPGATrackSimBinDesc.h"
+#include "FPGATrackSimBinStep.h"
+
+#include <GaudiKernel/GaudiHandle.h>
+#include <cmath>
+#include <string>
+#include <vector>
+
+// Use IdxSet and ParSet from FPGATrackSimUtil
+using FPGATrackSimBinUtil::ParSet;
+using FPGATrackSimBinUtil::IdxSet;
+
+//-------------------------------------------------------------------------------------------------------
+// 
+//-------------------------------------------------------------------------------------------------------
+class FPGATrackSimBinTool : virtual public AthAlgTool {
+public:
+  friend FPGATrackSimBinStep;
+
+  FPGATrackSimBinTool(const std::string &algname, const std::string &name,
+                      const IInterface *ifc)
+      : AthAlgTool(algname, name, ifc) {}
+  
+  virtual StatusCode initialize() override;
+
+  //--------------------------------------------------------------------------------------------------
+  //
+  //  Access to FPGATrackSimBinSteps and FPGATrackSimBinDesc
+  //
+  //--------------------------------------------------------------------------------------------------
+  const IFPGATrackSimBinDesc* binDesc() const {return m_binDesc.get();}
+  const ToolHandleArray<FPGATrackSimBinStep>& steps() const { return m_steps;}
+  FPGATrackSimBinStep* lastStep() { return (--m_steps.end())->get(); }
+  const FPGATrackSimBinStep* lastStep() const { return (--m_steps.end())->get(); }
+  const std::vector<std::string>& stepNames() const {return m_stepNames;}
+
+  //--------------------------------------------------------------------------------------------------
+  //
+  //  Bin Boundaries and conversions from value to bin
+  //
+  //--------------------------------------------------------------------------------------------------
+
+  // center of whole region
+  ParSet center() const;
+
+  // range of whole region
+  double parRange(unsigned par) const { return m_parMax[par]-m_parMin[par];}
+  double parMin(unsigned par) const { return m_parMin[par];}
+  double parMax(unsigned par) const { return m_parMax[par];}
+
+  // check if 1-d or 5-d parameter is within the range of the binning
+  bool inRange(unsigned par, double val) const { return ((val < m_parMax[par]) && (val > m_parMin[par])); }
+  bool inRange(const ParSet &pars) const;
+  
+  //--------------------------------------------------------------------------------------------------
+  //
+  //  Set which bins are valid
+  //
+  //--------------------------------------------------------------------------------------------------
+  void initValidBins();
+  void computeValidBins(const IFPGATrackSimEventSelectionSvc* evtSel);
+  void setValidBin(const std::vector<unsigned>& idx); // also sets SubBins
+  void printValidBin() const; // dump an output to log for x-checks
+
+private:
+  //--------------------------------------------------------------------------------------------------
+  //
+  // Python Configurables
+  //
+  //--------------------------------------------------------------------------------------------------
+  Gaudi::Property<double> m_d0FractionalPadding{this, "d0FractionalPadding", {}, "Fractional padding used when calculating the valid range of bins"};
+  Gaudi::Property<double> m_z0FractionalPadding{this, "z0FractionalPadding", {}, "Fractional padding used when calculating the valid range of bins"};
+  Gaudi::Property<double> m_etaFractionalPadding{this, "etaFractionalPadding", {}, "Fractional padding used when calculating the valid range of bins"};
+  Gaudi::Property<double> m_phiFractionalPadding{this, "phiFractionalPadding", {}, "Fractional padding used when calculating the valid range of bins"};
+  Gaudi::Property<double> m_qOverPtFractionalPadding{this, "qOverPtFractionalPadding", {}, "Fractional padding used when calculating the valid range of bins"};
+  Gaudi::Property<std::vector<float>> m_parMinConfig{this, "parMin", {}, "Vector of minimum bounds of parameters (expect 5"};
+  Gaudi::Property<std::vector<float>> m_parMaxConfig{this, "parMax", {}, "Vector of maximum bounds of parameters (expect 5"};
+
+  ToolHandleArray<FPGATrackSimBinStep> m_steps;
+  ToolHandle<IFPGATrackSimBinDesc> m_binDesc;
+
+  //
+  // Internal data
+  //
+
+  // These indicate the range of the full binning
+  ParSet m_parMin;
+  ParSet m_parMax;
+
+  // A list of the step names for convienience
+  std::vector<std::string> m_stepNames;
+};
+
+#endif // FPGATrackSimBinTool_H
diff --git a/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/IFPGATrackSimBinDesc.h b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/IFPGATrackSimBinDesc.h
new file mode 100644
index 0000000000000000000000000000000000000000..cddb85ad47c5a0c0863f2830e2fa81f1f5b64d57
--- /dev/null
+++ b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/FPGATrackSimBinning/IFPGATrackSimBinDesc.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
+
+#ifndef IFPGATrackSimBinDesc_H
+#define IFPGATrackSimBinDesc_H
+
+/**
+ * @file IFPGATrackSimBinDesc.h
+ * @author Elliot Lipeles
+ * @date Sept 10th, 2024
+ * @brief Defines Parameters used for binning
+ *
+ * Declarations in this file (there are a series of small classes):
+ *      class FPGATrackSimBinDesc
+ *      
+ * 
+ * Overview of stucture:
+ *    -- 
+ * 
+
+ * 
+ * References:
+ *
+ */
+#include "GaudiKernel/IAlgTool.h"
+
+#include "FPGATrackSimObjects/FPGATrackSimTrackPars.h"
+#include "FPGATrackSimObjects/FPGATrackSimHit.h"
+
+#include "FPGATrackSimBinning/FPGATrackSimBinUtil.h"
+
+#include <string>
+
+// Use IdxSet and ParSet from FPGATrackSimUtil
+using FPGATrackSimBinUtil::IdxSet;
+using FPGATrackSimBinUtil::ParSet;
+using FPGATrackSimBinUtil::StoredHit;
+class FPGATrackSimBinStep;
+
+//-------------------------------------------------------------------------------------------------------
+// BinnedHits
+//       Nomenclature:
+//          parameter = parameter of track e.g. (pT,eta,phi,d0,z0) but could be
+//          in different coordinates
+//             such at in the keylayer format where its
+//             (z_in,z_out,phi_in,phi_out,x_m)
+//          bin = a bin in the full parameters space (upto 5-d)
+//          subbin = a binning used as part of the total binning e.g. only in
+//          (pT,phi) or only in (z_in,z_out)
+//-------------------------------------------------------------------------------------------------------
+class IFPGATrackSimBinDesc : virtual public IAlgTool {
+public:
+  DeclareInterfaceID(IFPGATrackSimBinDesc, 1, 0);
+
+  //--------------------------------------------------------------------------------------------------
+  //
+  // Virtual methods that are overloaded to define the binning
+  //
+  //--------------------------------------------------------------------------------------------------
+
+  // Specification of parameters
+  virtual const std::string &parNames(unsigned i) const = 0;
+
+  // convert back and forth from pT, eta, phi, d0, z0 and internal paramater set
+  virtual const ParSet trackParsToParSet(const FPGATrackSimTrackPars &pars) const = 0;
+  virtual const FPGATrackSimTrackPars parSetToTrackPars(const ParSet &parset) const = 0;
+
+  // calculate the distance in phi or eta from a track defined by parset to a hit
+  // these can be implemented as any variable in the r-phi or r-eta plane (not necessarily eta and phi).
+  virtual double phiResidual(const ParSet &parset, FPGATrackSimHit const *hit) const = 0;
+  virtual double etaResidual(const ParSet &parset,  FPGATrackSimHit const *hit) const = 0;
+
+  // idx should be with the definition specifed in the step
+  // NOTE: the stored hit may be modified!
+  virtual bool hitInBin(const FPGATrackSimBinStep &step, const IdxSet &idx,
+                        StoredHit& storedhit) const = 0;
+
+private:
+  
+};
+
+#endif // IFPGATrackSimBinDesc_H
diff --git a/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/src/FPGATrackSimBinStep.cxx b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/src/FPGATrackSimBinStep.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..42e9b9b9bf6e60c9e57befceeed00a381be6ead1
--- /dev/null
+++ b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/src/FPGATrackSimBinStep.cxx
@@ -0,0 +1,151 @@
+
+// Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+
+/**
+ * @file FPGATrackSimGenScanBinDesc.cxx
+ * @author Elliot Lipeles
+ * @date Feb 13, 2025
+ * @brief See header file.
+ */
+
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+#include "FPGATrackSimBinning/FPGATrackSimBinTool.h"
+#include <GaudiKernel/StatusCode.h>
+#include "FPGATrackSimBinning/FPGATrackSimBinStep.h"
+
+StatusCode FPGATrackSimBinStep::initialize()
+{
+  // Dump the configuration to make sure it propagated through right
+  const std::vector<Gaudi::Details::PropertyBase*> props = this->getProperties();
+  for( Gaudi::Details::PropertyBase* prop : props ) {
+    if (prop->ownerTypeName()==this->type()) {      
+      ATH_MSG_DEBUG("Property:\t" << prop->name() << "\t : \t" << prop->toString());
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode FPGATrackSimBinStep::setRanges(const FPGATrackSimBinStep *prev,
+                                          const ParSet &parMin,
+                                          const ParSet &parMax) {
+  m_prev = prev;
+  if (prev) {
+    m_stepNum = prev->m_stepNum+1;
+  } else {
+    m_stepNum = 0;
+  }
+  m_parMin = parMin;
+  m_parMax = parMax;
+  m_parBins = std::vector<unsigned>(m_parBinsConfig);
+  for (unsigned par = 0; par < FPGATrackSimTrackPars::NPARS; par++) {
+    if (m_parBins[par] <= 0) {
+      ATH_MSG_FATAL("Every dimension must be at least one bin");
+      return StatusCode::FAILURE;
+    }
+    m_parStep[par] = (m_parMax[par] - m_parMin[par]) / m_parBins[par];
+
+    if (m_parBins[par] <= 0)
+    {
+      ATH_MSG_FATAL("Every dimension must be at least one bin (set #bins=1 for not binning in that parameter)");
+    }
+    if (m_parBins[par] < prev->m_parBins[par]) {
+      ATH_MSG_FATAL("Number of bins can only increase with each step");
+      return StatusCode::FAILURE;
+    }
+    if (m_parBins[par] % prev->m_parBins[par] !=0) {
+      ATH_MSG_FATAL("Number of bins must be integer multiple of bins in previous step");
+      return StatusCode::FAILURE;
+    }
+    if (m_parBins[par] != prev->m_parBins[par]) {
+      // This step involves this parameter
+      m_pars.push_back(par);      
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+ParSet FPGATrackSimBinStep::binLowEdge(const IdxSet &idx) const
+{
+    ParSet parset;
+    for (unsigned i = 0; i < FPGATrackSimTrackPars::NPARS; i++)
+    {
+        parset[i] = binLowEdge(i, idx[i]);
+    }
+    return parset;
+}
+
+ParSet FPGATrackSimBinStep::binCenter(const IdxSet &idx) const
+{
+    ParSet parset;
+    for (unsigned i = 0; i < FPGATrackSimTrackPars::NPARS; i++)
+    {
+        parset[i] = binCenter(i, idx[i]);
+    }
+    return parset;
+}
+
+IdxSet FPGATrackSimBinStep::binIdx(const ParSet &pars) const
+{
+    IdxSet retv;
+    for (unsigned i = 0; i < FPGATrackSimTrackPars::NPARS; i++)
+    {
+        retv[i] = binIdx(i, pars[i]);
+    }
+    return retv;
+}
+
+
+
+// Convert to previous steps idx
+IdxSet FPGATrackSimBinStep::convertToPrev(const IdxSet &cur) const {
+  IdxSet retv;
+  if (m_prev) {
+    for (unsigned par =0; par < FPGATrackSimTrackPars::NPARS; par++) {
+      retv[par] = (cur[par]*m_prev->m_parBins[par]/m_parBins[par]);
+    }
+  } else {
+    ATH_MSG_FATAL("convertToPrev called, but no previous");
+  }
+  return retv;
+}
+
+
+const std::vector<unsigned> FPGATrackSimBinStep::stepIdx(IdxSet idx) const {
+       return FPGATrackSimBinUtil::subVec(m_pars, idx);}
+  
+const std::vector<unsigned> FPGATrackSimBinStep::stepBins() const {
+    return FPGATrackSimBinUtil::subVec(m_pars, m_parBins);}
+
+void FPGATrackSimBinStep::setValidBin(const std::vector<unsigned>& idx) {
+  m_validBinFull[idx] = true;
+  m_validBinLocal[stepIdx(idx)] = true;
+  if (m_prev) setValidBin(convertToPrev(idx));
+}
+
+void FPGATrackSimBinStep::initValidBins() {
+  m_validBinFull.setsize(m_parBins, false);
+  m_validBinLocal[stepBins()] = true;
+}
+
+void FPGATrackSimBinStep::printValidBin() const {
+  // count valid bins
+  int validBinsFull = 0;
+  
+  for (FPGATrackSimBinArray<int>::ConstIterator bin : m_validBinFull) {
+    if (bin.data())
+      validBinsFull++;
+  }
+  ATH_MSG_INFO("Step" << m_name<< "Valid Bins Full: " << validBinsFull);
+
+  // count valid bins
+  int validBinsLocal = 0;
+  for (FPGATrackSimBinArray<int>::ConstIterator bin : m_validBinLocal) {
+  if (bin.data())
+    validBinsLocal++;
+  }
+  ATH_MSG_INFO("Step" << m_name<<  "Valid Bins Local: " << validBinsLocal);
+  
+}
+
diff --git a/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/src/FPGATrackSimBinTool.cxx b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/src/FPGATrackSimBinTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d6bf3922109cdd193e79e9bdcc2141b2c2817038
--- /dev/null
+++ b/Trigger/EFTracking/FPGATrackSim/FPGATrackSimBinning/src/FPGATrackSimBinTool.cxx
@@ -0,0 +1,132 @@
+// Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+
+/**
+ * @file PGATrackSimGenScanTool.cxx
+ * @author Elliot Lipeles
+ * @date Feb 13, 2025
+ * @brief See header file.
+ */
+
+#include "FPGATrackSimBinning/FPGATrackSimBinTool.h"
+
+
+// ----------------------------------------------------------------------------------------
+//  AthTool Methods
+// ----------------------------------------------------------------------------------------
+
+StatusCode FPGATrackSimBinTool::initialize() {
+  // Retrieve
+  ATH_MSG_INFO("Using " << m_steps.size() << " steps");
+  ATH_CHECK(m_steps.retrieve());
+
+  if (m_steps.empty()) {
+    ATH_MSG_FATAL("initialize() Step list empty");
+    return StatusCode::FAILURE;
+  }
+
+  FPGATrackSimBinStep* prev = 0;
+  for (auto &step : m_steps) {
+    ATH_MSG_INFO("Got Binning Step " << step->stepName());
+    m_stepNames.push_back(step->stepName());
+    if (step->setRanges(prev, m_parMin, m_parMax)) {
+      ATH_MSG_FATAL("Failed to setRange on step");
+      return StatusCode::FAILURE;
+    }
+    prev = step.get();
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------------------------
+//  Other methods
+// ----------------------------------------------------------------------------------------
+
+bool FPGATrackSimBinTool::FPGATrackSimBinTool::inRange(
+    const ParSet &parset) const {
+  for (unsigned par = 0; par < FPGATrackSimTrackPars::NPARS; par++) {
+    if (!inRange(par,parset[par]))
+      return false;
+  }
+  return true;
+}
+
+// ----------------------------------------------------------------------------------------
+//  Valid Bin Function Implementation
+// ----------------------------------------------------------------------------------------
+
+void FPGATrackSimBinTool::setValidBin(const std::vector<unsigned>& idx) {
+  lastStep()->setValidBin(idx);
+}
+
+void FPGATrackSimBinTool::initValidBins() {
+  for (auto& step: m_steps) step->initValidBins();
+}
+
+void FPGATrackSimBinTool::printValidBin() const {
+  for (auto &step : m_steps) {
+    step->printValidBin();
+  }
+}
+
+// Compute which bins correspond to track parameters that are in the region
+// i.e. the pT, eta, phi, z0 and d0 bounds
+void FPGATrackSimBinTool::computeValidBins(const IFPGATrackSimEventSelectionSvc* evtSel) {
+  // determine which bins are valid
+  
+  FPGATrackSimTrackPars min_padded;
+  FPGATrackSimTrackPars max_padded;
+  FPGATrackSimTrackPars padding;
+  padding[FPGATrackSimTrackPars::ID0] = m_d0FractionalPadding;
+  padding[FPGATrackSimTrackPars::IZ0] = m_z0FractionalPadding;
+  padding[FPGATrackSimTrackPars::IETA] = m_etaFractionalPadding;
+  padding[FPGATrackSimTrackPars::IPHI] = m_phiFractionalPadding;
+  padding[FPGATrackSimTrackPars::IHIP] = m_qOverPtFractionalPadding;
+  for (unsigned par = 0; par < FPGATrackSimTrackPars::NPARS; par++)
+  {
+    min_padded[par] = evtSel->getMin()[par] - padding[par] * (evtSel->getMax()[par]-evtSel->getMin()[par]);
+    max_padded[par] = evtSel->getMax()[par] + padding[par] * (evtSel->getMax()[par]-evtSel->getMin()[par]);
+    if (par==FPGATrackSimTrackPars::IHIP) {
+      // working in units of GeV internally
+      min_padded[par] *= 1000;
+      max_padded[par] *= 1000;
+    }
+    ATH_MSG_INFO("Padded Parameter Range: " << FPGATrackSimTrackPars::parName(par)
+                                            << " min=" << min_padded[par] << " max=" << max_padded[par]);
+  }
+
+  // iterator over the finest binning used which is the laststep
+  // setting lastSteps valid bins sets all the previous steps
+  auto laststep = lastStep();
+  for (FPGATrackSimBinArray<int>::Iterator bin : laststep->m_validBinFull) 
+  {
+    // this finds the parameters at all 2^5 corners of the bin and then finds the min and max of those
+    std::vector<IdxSet> idxsets = FPGATrackSimBinUtil::makeVariationSet(std::vector<unsigned>({0,1,2,3,4}),bin.idx());
+    FPGATrackSimTrackPars minvals = m_binDesc->parSetToTrackPars(laststep->binCenter(bin.idx()));
+    FPGATrackSimTrackPars maxvals = m_binDesc->parSetToTrackPars(laststep->binCenter(bin.idx()));
+    for (IdxSet & idxset : idxsets) {
+      FPGATrackSimTrackPars trackpars = m_binDesc->parSetToTrackPars(laststep->binLowEdge(idxset));
+      for (unsigned par =0; par < FPGATrackSimTrackPars::NPARS; par++) {
+        minvals[par] = std::min(minvals[par],trackpars[par]);
+        maxvals[par] = std::max(maxvals[par],trackpars[par]);
+      }
+    }
+
+    // make sure bin overlaps with active region
+    bool inRange = true;
+    for (unsigned par =0; par < FPGATrackSimTrackPars::NPARS; par++) {
+      inRange = inRange && (minvals[par] < max_padded[par]) && (maxvals[par] > min_padded[par]);
+    }
+    if (inRange)
+    {
+      setValidBin(bin.idx()); 
+    }
+
+    if (bin.data() == false)
+    {
+      ATH_MSG_VERBOSE("Invalid bin: " << bin.idx() << " :" << m_binDesc->parSetToTrackPars(laststep->binCenter(bin.idx()))
+      << " minvals: " << minvals << " maxvals: " << maxvals );
+    }
+  }
+}
+