From 622e95bd747dba67b5f453748fb66468d72aa730 Mon Sep 17 00:00:00 2001
From: Dave Casper <dcasper@localhost.localdomain>
Date: Wed, 15 Jan 2020 23:59:15 -0800
Subject: [PATCH] First version of SCT_Digitization

---
 .../FaserSCT_Digitization/CMakeLists.txt      |    4 +-
 .../FaserSCT_Digitization/src/SCT_Amp.cxx     |  143 +++
 .../FaserSCT_Digitization/src/SCT_Amp.h       |   69 ++
 .../src/SCT_Digitization.cxx                  |   31 +
 .../src/SCT_Digitization.h                    |   48 +
 .../src/SCT_FrontEnd.cxx                      | 1044 +++++++++++++++++
 .../FaserSCT_Digitization/src/SCT_FrontEnd.h  |  140 +++
 .../src/SCT_RandomDisabledCellGenerator.cxx   |   40 +
 .../src/SCT_RandomDisabledCellGenerator.h     |   67 ++
 .../src/SCT_SurfaceChargesGenerator.cxx       |  578 +++++++++
 .../src/SCT_SurfaceChargesGenerator.h         |  164 +++
 .../FaserSCT_Digitization_entries.cxx         |   24 +-
 .../TrackerSimEvent/FaserSiHit.h              |    4 +-
 13 files changed, 2341 insertions(+), 15 deletions(-)
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.cxx
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.h
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.cxx
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.h
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.cxx
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.h
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.cxx
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.h
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx
 create mode 100644 Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.h

diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/CMakeLists.txt b/Tracker/TrackerDigitization/FaserSCT_Digitization/CMakeLists.txt
index e836c3e3..d0965e8d 100644
--- a/Tracker/TrackerDigitization/FaserSCT_Digitization/CMakeLists.txt
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/CMakeLists.txt
@@ -24,7 +24,7 @@ atlas_depends_on_subdirs( PUBLIC
                           Generators/GeneratorObjects
                           #InnerDetector/InDetConditions/InDetConditionsSummaryService
                           #InnerDetector/InDetConditions/SCT_ConditionsTools
-                          #InnerDetector/InDetConditions/SiPropertiesTool
+                          InnerDetector/InDetConditions/SiPropertiesTool
                           Tracker/TrackerDetDescr/TrackerIdentifier
                           Tracker/TrackerDetDescr/TrackerReadoutGeometry
                           #InnerDetector/InDetDetDescr/SCT_ModuleDistortions
@@ -40,7 +40,7 @@ atlas_add_component( FaserSCT_Digitization
                      src/*.cxx
                      src/components/*.cxx
                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CLHEP_LIBRARIES} AthenaBaseComps AthenaKernel PileUpToolsLib Identifier xAODEventInfo GaudiKernel FaserSiDigitization InDetRawData TrackerSimEvent HitManagement GeneratorObjects TrackerIdentifier TrackerReadoutGeometry InDetSimData )
+                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CLHEP_LIBRARIES} AthenaBaseComps AthenaKernel PileUpToolsLib Identifier xAODEventInfo GaudiKernel FaserSiDigitization InDetRawData TrackerSimEvent HitManagement GeneratorObjects SiPropertiesToolLib TrackerIdentifier TrackerReadoutGeometry InDetSimData )
 #                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CLHEP_LIBRARIES} CommissionEvent AthenaBaseComps AthenaKernel PileUpToolsLib Identifier xAODEventInfo GaudiKernel SiDigitization InDetRawData InDetSimEvent HitManagement GeneratorObjects SiPropertiesToolLib InDetIdentifier InDetReadoutGeometry InDetSimData )
 
 #atlas_add_test( SCT_DigitizationMT_test
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.cxx b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.cxx
new file mode 100644
index 00000000..22352b26
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.cxx
@@ -0,0 +1,143 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "SCT_Amp.h"
+
+// CLHEP
+#include "CLHEP/Units/SystemOfUnits.h"
+
+//STD includes
+#include <cmath>
+#include <fstream>
+
+//#define SCT_DIG_DEBUG
+
+// constructor
+SCT_Amp::SCT_Amp(const std::string& type, const std::string& name, const IInterface* parent) 
+  : base_class(type, name, parent)
+{
+}
+
+//----------------------------------------------------------------------
+// Initialize
+//----------------------------------------------------------------------
+StatusCode SCT_Amp::initialize() {
+  
+  StatusCode sc{AthAlgTool::initialize()};
+  if (sc.isFailure()) {
+    ATH_MSG_FATAL("SCT_Amp::initialize() failed");
+    return sc;
+  }
+  ATH_MSG_DEBUG("SCT_Amp::initialize()");
+
+  /** CHLEP Units */
+  m_PeakTime.setValue(m_PeakTime.value() * CLHEP::ns);
+  m_dt.setValue(m_dt.value() * CLHEP::ns);
+  m_tmin.setValue(m_tmin.value() * CLHEP::ns);
+  m_tmax.setValue(m_tmax.value() * CLHEP::ns);
+
+  m_NormConstCentral = (exp(3.0)/27.0)*(1.0-m_CrossFactor2sides)*(1.0-m_CrossFactorBack);
+  m_NormConstNeigh = exp(3.0-sqrt(3.0))/(6*(2.0*sqrt(3.0)-3.0));
+  m_NormConstNeigh *= (m_CrossFactor2sides/2.0)*(1.0-m_CrossFactorBack);
+
+#ifdef SCT_DIG_DEBUG
+  ATH_MSG_INFO("\tAmp created, PeakTime = " << m_PeakTime);
+  ATH_MSG_INFO("\tResponse will be CR-RC^3 with tp = " << m_PeakTime/3.0);
+  ATH_MSG_INFO("\tCoupling to both neighbours = " << m_CrossFactor2sides);
+  ATH_MSG_INFO("\tCoupling to backplane = " << m_CrossFactorBack);
+  ATH_MSG_INFO("\tNormalization for central " << m_NormConstCentral);
+  ATH_MSG_INFO("\tNormalization for neighbour " << m_NormConstNeigh);
+#endif
+
+  return sc;
+}
+
+//----------------------------------------------------------------------
+// Finalize 
+//----------------------------------------------------------------------
+StatusCode SCT_Amp::finalize() {
+  StatusCode sc{AthAlgTool::finalize()};
+  if (sc.isFailure()) {
+    ATH_MSG_FATAL("SCT_Amp::finalize() failed");
+    return sc;
+  }
+  ATH_MSG_DEBUG("SCT_Amp::finalize()");
+  return sc;
+}
+
+//----------------------------------------------------------------------
+// Electronique response is now CR-RC^3 of the charge diode
+//----------------------------------------------------------------------
+float SCT_Amp::response(const list_t& Charges, const float timeOfThreshold) const {
+  float resp{0.0};
+  float tp{static_cast<float>(m_PeakTime/3.0)}; // for CR-RC^3
+  for (const SiCharge& charge: Charges) {
+    float ch{static_cast<float>(charge.charge())};
+    float tC{static_cast<float>(timeOfThreshold - charge.time())};
+    if (tC > 0.0) {
+      tC/=tp; //to avoid doing it four times
+      resp += ch*tC*tC*tC*exp(-tC); //faster than pow
+    }
+  }
+  return resp*m_NormConstCentral;
+}
+
+void SCT_Amp::response(const list_t& Charges, const float timeOfThreshold, std::vector<float>& response) const {
+  short bin_max{static_cast<short>(response.size())};
+  std::fill(response.begin(), response.end(), 0.0);
+  float tp{static_cast<float>(m_PeakTime/3.0)}; // for CR-RC^3
+  for (const SiCharge& charge: Charges) {
+    float ch{static_cast<float>(charge.charge())};
+    float ch_time{static_cast<float>(charge.time())};
+    short bin_end{static_cast<short>(bin_max-1)};
+    for (short bin{-1}; bin<bin_end; ++bin) {
+      float bin_timeOfThreshold{timeOfThreshold + bin*25};//25, fix me
+      float tC{bin_timeOfThreshold - ch_time};
+      if (tC > 0.0) {
+        tC/=tp; //to avoid doing it four times
+        response[bin+1] += ch*tC*tC*tC*exp(-tC); //faster than pow
+      }
+    }
+  }
+  for (short bin{0}; bin<bin_max; ++bin) response[bin] = response[bin]*m_NormConstCentral;
+  return;
+}
+
+//----------------------------------------------------------------------
+// differenciated and scaled pulse on the neighbour strip! 
+//----------------------------------------------------------------------
+float SCT_Amp::crosstalk(const list_t& Charges, const float timeOfThreshold) const {
+  float resp{0};
+  float tp{static_cast<float>(m_PeakTime/3.0)}; // for CR-RC^3
+  for (const SiCharge& charge: Charges) {
+    float ch{static_cast<float>(charge.charge())};
+    float tC{static_cast<float>(timeOfThreshold - charge.time())};
+    if (tC > 0.0) {
+      tC/=tp; //to avoid doing it four times
+      resp += ch*tC*tC*exp(-tC)*(3.0-tC); //faster than pow
+    }
+  }
+  return resp*m_NormConstNeigh;
+}
+
+void SCT_Amp::crosstalk(const list_t& Charges, const float timeOfThreshold, std::vector<float>& response) const {
+  short bin_max{static_cast<short>(response.size())};
+  std::fill(response.begin(), response.end(), 0.0);
+  float tp{static_cast<float>(m_PeakTime/3.0)}; // for CR-RC^3
+  for (const SiCharge& charge: Charges) {
+    float ch{static_cast<float>(charge.charge())};
+    float ch_time{static_cast<float>(charge.time())};
+    short bin_end{static_cast<short>(bin_max-1)};
+    for (short bin{-1}; bin<bin_end; ++bin) {
+      float bin_timeOfThreshold{timeOfThreshold + bin*25}; // 25, fix me
+      float tC{bin_timeOfThreshold - ch_time};
+      if (tC > 0.0) {
+        tC/=tp; //to avoid doing it four times
+        response[bin+1] += ch*tC*tC*exp(-tC)*(3.0-tC); //faster than pow
+      }
+    }
+  }
+  for (short bin{0}; bin<bin_max; ++bin) response[bin] = response[bin]*m_NormConstNeigh;
+  return;
+}
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.h b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.h
new file mode 100644
index 00000000..d066e194
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Amp.h
@@ -0,0 +1,69 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ *  Header file for SCT_Amp Class  
+ *  @brief A class to model an SCT amplifier and shaper. Gives a CRRC response to a 
+ *  list of charges with times. Also calculates average input and output for 
+ *  diagnostic purposes. Questions/comments to Szymon.Gadomski@cern.ch
+ *  Name changed from SCTpreamp (misleading) on 09.05.01. 
+ *  @author Szymon.Gadomski@cern.ch, Awatif.Belymam@cern.ch, Davide.Costanzo@cern.ch,
+ *  tgcornel@nikhef.nl, Grant.Gorfine@cern.ch, Paul.Bell@cern.ch, Jorgen.Dalmau@cern.ch, 
+ * 23/08/2007 - Kondo.Gnanvo@cern.ch 
+ *            - Conversion of the SCT_Amp code AlgTool 
+ */
+
+#ifndef FASERSCT_DIGITIZATION_SCTAMP_H
+#define FASERSCT_DIGITIZATION_SCTAMP_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "FaserSCT_Digitization/ISCT_Amp.h"
+
+#include "TrackerSimEvent/SiCharge.h"
+
+class SCT_Amp : public extends<AthAlgTool, ISCT_Amp> {
+ public:
+
+  /**  constructor */
+  SCT_Amp(const std::string& type, const std::string& name, const IInterface* parent);
+  /** Destructor */
+  virtual ~SCT_Amp() = default;
+  /** AlgTool initialize */
+  virtual StatusCode initialize() override;
+  /** AlgTool finalize */
+  virtual StatusCode finalize() override;
+   
+  /** main purpose: CR-RC^3 response to a list of charges with times */
+  virtual float response(const list_t& Charges, const float timeOverThreshold) const override;
+  virtual void response(const list_t& Charges, const float timeOverThreshold, std::vector<float>& resp) const override;
+
+  /** Neighbour strip cross talk response strip to a list of charges with times */
+  virtual float crosstalk(const list_t& Charges, const float timeOverThreshold) const override;
+  virtual void crosstalk(const list_t& Charges, const float timeOverThreshold, std::vector<float>& resp) const override;
+
+private:
+
+  /** signal peak time */   
+  FloatProperty m_PeakTime{this, "PeakTime", 21., "Front End Electronics peaking time"};
+
+  /** Cross factor 2 side */
+  FloatProperty m_CrossFactor2sides{this, "CrossFactor2sides", 0.1, "Loss of charge to neighbour strip constant"};
+
+  /** cross factor */
+  FloatProperty m_CrossFactorBack{this, "CrossFactorBack", 0.07, "Loss of charge to back plane constant"};
+
+  FloatProperty m_tmin{this, "Tmin", -25.0};
+  FloatProperty m_tmax{this, "Tmax", 150.0};
+  FloatProperty m_dt{this, "deltaT", 1.0};
+
+  /** Normalisation factor for the signal response */
+  float m_NormConstCentral{0.};
+
+  /** Normalisation factor for the neighbour strip signal response */
+  float m_NormConstNeigh{0.};
+};
+
+#endif // FASERSCT_DIGITIZATION_SCTAMP_H
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.cxx b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.cxx
new file mode 100644
index 00000000..f30bbd62
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.cxx
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "SCT_Digitization.h"
+#include "PileUpTools/IPileUpTool.h"
+
+//----------------------------------------------------------------------
+// Constructor with parameters:
+//----------------------------------------------------------------------
+SCT_Digitization::SCT_Digitization(const std::string& name, ISvcLocator* pSvcLocator) :
+  AthAlgorithm(name, pSvcLocator)
+{
+}
+
+//----------------------------------------------------------------------
+// Initialize method:
+//----------------------------------------------------------------------
+StatusCode SCT_Digitization::initialize() {
+  ATH_MSG_DEBUG("SCT_Digitization::initialize()");
+  return StatusCode::SUCCESS ;
+}
+
+//----------------------------------------------------------------------
+// Execute method:
+//----------------------------------------------------------------------
+
+StatusCode SCT_Digitization::execute() {
+  ATH_MSG_DEBUG("execute()");
+  return m_sctDigitizationTool->processAllSubEvents();
+}
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.h b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.h
new file mode 100644
index 00000000..3f32cdf0
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_Digitization.h
@@ -0,0 +1,48 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** @file SCT_Digitization.h  Header file for SCT_Digitization class.
+ *  @author Szymon.Gadomski@cern.ch, Awatif.Belymam@cern.ch, Davide.Costanzo@cern.ch,
+ *          tgcornel@nikhef.nl, Grant.Gorfine@cern.ch, Paul.Bell@cern.ch,
+ *          Jorgen.Dalmau@cern.ch, Kondo.Gnanvo@cern.ch, and others
+ * Version 23/08/2007 Kondo.Gnanvo@cern.ch
+ *          Conversion of the processors into AlgTool
+ */
+
+// Multiple inclusion protection
+#ifndef FASERSCT_DIGITIZATION_SCT_DIGITIZATION_H
+#define FASERSCT_DIGITIZATION_SCT_DIGITIZATION_H
+
+// Base class
+#include "AthenaBaseComps/AthAlgorithm.h"
+// Gaudi
+#include "GaudiKernel/ToolHandle.h"
+
+class IPileUpTool;
+
+/** Top algorithm class for SCT digitization */
+class SCT_Digitization : public AthAlgorithm {
+
+ public:
+
+  /** Constructor with parameters */
+  SCT_Digitization(const std::string& name, ISvcLocator* pSvcLocator);
+
+  /** Destructor */
+  virtual ~SCT_Digitization() = default;
+
+  /** Basic algorithm methods */
+  virtual StatusCode initialize() override final;
+  virtual StatusCode execute() override final;
+  virtual bool isClonable() const override final { return true; }
+
+ private:
+
+  ToolHandle<IPileUpTool> m_sctDigitizationTool{this, "DigitizationTool", "SCT_DigitizationTool", "SCT_DigitizationTool name"};
+
+};
+
+#endif // FASERSCT_DIGITIZATION_SCT_DIGITIZATION_H
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.cxx b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.cxx
new file mode 100644
index 00000000..50d06c46
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.cxx
@@ -0,0 +1,1044 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "SCT_FrontEnd.h"
+
+// Random number
+#include "CLHEP/Random/RandFlat.h"
+#include "CLHEP/Random/RandGaussZiggurat.h"  // for RandGaussZiggurat
+#include "CLHEP/Random/RandPoisson.h"
+#include "CLHEP/Random/RandomEngine.h"
+
+#include "FaserSiDigitization/SiHelper.h"
+#include "FaserSCT_Digitization/ISCT_Amp.h"
+
+#include "TrackerIdentifier/FaserSCT_ID.h"
+
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerReadoutGeometry/SCT_ModuleSideDesign.h"
+
+// C++ Standard Library
+#include <algorithm>
+#include <iostream>
+
+// #define SCT_DIG_DEBUG
+
+using namespace std;
+using namespace TrackerDD;
+
+// constructor
+SCT_FrontEnd::SCT_FrontEnd(const std::string& type, const std::string& name, const IInterface* parent)
+  : base_class(type, name, parent) {
+}
+
+// ----------------------------------------------------------------------
+// Initialize
+// ----------------------------------------------------------------------
+StatusCode SCT_FrontEnd::initialize() {
+  if (m_NoiseOn and (not m_analogueNoiseOn)) {
+    ATH_MSG_FATAL("AnalogueNoiseOn/m_analogueNoiseOn should be true if NoiseOn/m_NoiseOn is true.");
+    return StatusCode::FAILURE;
+  }
+
+  ATH_MSG_DEBUG("SCT_FrontEnd::initialize()");
+  // Get SCT helper
+  ATH_CHECK(detStore()->retrieve(m_sct_id, "FaserSCT_ID"));
+  // Get SCT detector manager
+  ATH_CHECK(detStore()->retrieve(m_SCTdetMgr, "SCT"));
+  // Get the amplifier tool
+  ATH_CHECK(m_sct_amplifier.retrieve());
+  ATH_MSG_DEBUG("SCT Amplifier tool located ");
+
+  // Get the SCT_ReadCaliDataSvc
+  if (m_useCalibData) {
+    // ATH_CHECK(m_ReadCalibChipDataTool.retrieve());
+    // ATH_MSG_DEBUG("CalibChipData Service located ");
+    ATH_MSG_FATAL("Use of calibration data not supported.");
+  } else {
+    // m_ReadCalibChipDataTool.disable();
+  }
+
+  // Get the maximum number of strips of any module
+  m_strip_max = m_SCTdetMgr->numerology().maxNumStrips();
+
+  constexpr float fC = 6242.2;
+  m_Threshold = m_Threshold * fC;
+
+#ifdef SCT_DIG_DEBUG
+  ATH_MSG_INFO("\tNoise factors:");
+  ATH_MSG_INFO("\tBarrel = " << m_NoiseBarrel << " Outer Barrel = " << m_NoiseBarrel3 <<
+               " EC, inners = " << m_NoiseInners << " EC, middles = " << m_NoiseMiddles <<
+               " EC, short middles = " << m_NoiseShortMiddles << " EC, outers = " << m_NoiseOuters);
+  ATH_MSG_INFO("\tThreshold=" << m_Threshold << " fC, time of Threshold=" << m_timeOfThreshold);
+#endif
+
+  ATH_MSG_INFO("m_Threshold             (Threshold)           = " << m_Threshold);
+  ATH_MSG_INFO("m_timeOfThreshold       (TimeOfThreshold)     = " << m_timeOfThreshold);
+  ATH_MSG_INFO("m_data_compression_mode (DataCompressionMode) = " << m_data_compression_mode);
+  ATH_MSG_INFO("m_data_readout_mode     (DataReadOutMode)     = " <<  m_data_readout_mode);
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode SCT_FrontEnd::finalize() {
+#ifdef SCT_DIG_DEBUG
+  ATH_MSG_INFO("SCT_FrontEnd::finalize()");
+#endif
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+// Init the class variable  vectors
+// ----------------------------------------------------------------------
+StatusCode SCT_FrontEnd::initVectors(int strips, SCT_FrontEndData& data) const {
+  data.m_Offset.assign(strips, 0.0);
+  data.m_GainFactor.assign(strips, 0.0);
+  data.m_NoiseFactor.assign(strips, 0.0);
+
+  if (m_data_compression_mode == 1 and m_data_readout_mode == 0) {
+    data.m_Analogue[0].reserve(1);
+    data.m_Analogue[1].reserve(strips);
+  } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) {
+    data.m_Analogue[0].reserve(strips);
+    data.m_Analogue[1].reserve(strips);
+  } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) {
+    data.m_Analogue[0].reserve(strips);
+    data.m_Analogue[1].reserve(strips);
+    data.m_Analogue[2].reserve(strips);
+  } else {
+    return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+// prepare gain and offset for the strips for a given module
+// ----------------------------------------------------------------------
+StatusCode SCT_FrontEnd::prepareGainAndOffset(SiChargedDiodeCollection& collection, /*const Identifier& moduleId,*/ CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data) const {
+  // now we need to generate gain and offset channel by channel: some algebra
+  // for generation of partially correlated random numbers
+  float W = m_OGcorr * m_GainRMS * m_Ospread / (m_GainRMS * m_GainRMS - m_Ospread * m_Ospread);
+  float A = 4 * W * W + 1.0;
+  float x1 = (A - sqrt(A)) / (2.0 * A);
+  float sinfi = sqrt(x1);
+  float cosfi = sqrt(1.0 - x1);
+
+  sinfi = sinfi * m_OGcorr / fabs(m_OGcorr);
+  float S = m_GainRMS * m_GainRMS + m_Ospread * m_Ospread;
+  float D = (m_GainRMS * m_GainRMS - m_Ospread * m_Ospread) / (cosfi * cosfi - sinfi * sinfi);
+  float S1 = sqrt((S + D) * 0.5);
+  float S2 = sqrt((S - D) * 0.5);
+  float Noise = 0;
+  int mode = 1;
+
+  // To set noise values for different module types, barrel, EC, inners, middles, short middles, and outers
+  if (m_analogueNoiseOn) {
+    // if (m_sct_id->barrel_ec(moduleId) == 0) { // barrel_ec=0 corresponds to barrel
+    //   if (m_sct_id->layer_disk(moduleId) == 3) { // outer barrel layer 10 degrees warmer
+        Noise = m_NoiseBarrel3;
+    //   } else {
+    //     Noise = m_NoiseBarrel;
+    //   }
+    // } else {
+    //   int moduleType = m_sct_id->eta_module(moduleId);
+    //   switch (moduleType) { // eta = 0, 1, or 2 corresponds to outers, middles and inners?! (at least in the offline world)
+    //   case 0: {
+    //     Noise = m_NoiseOuters;
+    //     break;
+    //   }
+    //   case 1: {
+    //     if (m_sct_id->layer_disk(moduleId) == 7) {
+    //       Noise = m_NoiseShortMiddles;
+    //     } else {
+    //       Noise = m_NoiseMiddles;
+    //     }
+    //     break;
+    //   }
+    //   case 2: {
+    //     Noise = m_NoiseInners;
+    //     break;
+    //   }
+    //   default: {
+    //     Noise = m_NoiseBarrel;
+    //     ATH_MSG_ERROR("moduleType(eta): " << moduleType << " unknown, using barrel");
+    //   }
+    //   }// end of switch structure
+    // }
+  }
+
+  // Loop over collection and setup gain/offset/noise for the hit and neighbouring strips
+  SiChargedDiodeIterator i_chargedDiode = collection.begin();
+  SiChargedDiodeIterator i_chargedDiode_end = collection.end();
+
+  for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
+    SiChargedDiode diode = (*i_chargedDiode).second;
+    // should be const as we aren't trying to change it here - but getReadoutCell() is not a const method...
+    unsigned int flagmask = diode.flag() & 0xFE;
+    // Get the flag for this diode ( if flagmask = 1 If diode is disconnected/disabled skip it)
+    if (!flagmask) { // If the diode is OK (not flagged)
+      const SiReadoutCellId roCell = diode.getReadoutCell();
+      if (roCell.isValid()) {
+        int strip = roCell.strip();
+        int i = std::max(strip - 1, 0);
+        int i_end = std::min(strip + 2, m_strip_max.load());
+
+        // loop over strips
+        for (; i < i_end; i++) {
+          // Need to check if strip is already setup
+          if (data.m_Analogue[1][i] <= 0.0) {
+            float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S1);
+            float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S2);
+
+            data.m_GainFactor[i] = 1.0 + (cosfi * g + sinfi * o);
+            data.m_Offset[i] = (cosfi * o - sinfi * g);
+            data.m_NoiseFactor[i] = Noise * mode;
+
+            // Fill the noise and offset values into the Analogue
+            if (m_data_compression_mode == 1 and m_data_readout_mode == 0) { // level mode x1x
+              data.m_Analogue[1][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+            } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) { // edge mode 01x
+              data.m_Analogue[0][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+              data.m_Analogue[1][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+            } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) { // any hit mode xxx or expanded read out mode
+              data.m_Analogue[0][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+              data.m_Analogue[1][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+              data.m_Analogue[2][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+// prepare gain and offset for the strips for a given module using
+// Cond Db data to get the chip calibration data
+// ----------------------------------------------------------------------
+// StatusCode SCT_FrontEnd::prepareGainAndOffset(SiChargedDiodeCollection& collection, int side, const Identifier& moduleId, CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data) const {
+//   // Get chip data from calib DB
+//   std::vector<float> gainByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "GainByChip");
+//   std::vector<float> gainRMSByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "GainRMSByChip");
+//   std::vector<float> offsetByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "OffsetByChip");
+//   std::vector<float> offsetRMSByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "OffsetRMSByChip");
+//   std::vector<float> noiseByChipVect(6, 0.0);
+
+//   if (m_analogueNoiseOn) { // Check if noise should be on or off
+//     noiseByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "NoiseByChip");
+//   }
+
+//   // Need to check if empty, most should have data, but a few old DEAD modules don't
+//   if (gainByChipVect.empty() or noiseByChipVect.empty()) {
+//     ATH_MSG_DEBUG("No calibration data in cond DB for module " << moduleId << " using JO values");
+//     if (StatusCode::SUCCESS != prepareGainAndOffset(collection, moduleId, rndmEngine, data)) {
+//       return StatusCode::FAILURE;
+//     } else {
+//       return StatusCode::SUCCESS;
+//     }
+//   }
+
+//   // Don't really need to set up values for each chip...
+//   float gainMeanValue = meanValue(gainByChipVect);
+//   if (gainMeanValue < 0.0) {
+//     ATH_MSG_DEBUG("All chip gain values are 0 for module " << moduleId << " using JO values");
+//     if (StatusCode::SUCCESS != prepareGainAndOffset(collection, moduleId, rndmEngine, data)) {
+//       return StatusCode::FAILURE;
+//     } else {
+//       return StatusCode::SUCCESS;
+//     }
+//   }
+
+//   std::vector<float> gain(6, 0.0);
+//   std::vector<float> offset(6, 0.0);
+//   std::vector<float> S1(6, 0.0);
+//   std::vector<float> S2(6, 0.0);
+//   std::vector<float> sinfi(6, 0.0);
+//   std::vector<float> cosfi(6, 0.0);
+//   float gainRMS = 0.0;
+//   float offsetRMS = 0.0;
+
+//   for (int i = 0; i < 6; ++i) {
+//     // Some very few chips have 0 values, dead/bypassed/etc, so check and use some fixed values instead
+//     if (gainByChipVect[i] > 0.1) {
+//       gain[i] = gainByChipVect[i] / gainMeanValue;
+//       offset[i] = offsetByChipVect[i] / m_Threshold;
+//       gainRMS = gainRMSByChipVect[i] / gainMeanValue;
+//       offsetRMS = offsetRMSByChipVect[i] / m_Threshold;
+//     } else {
+//       gain[i] = 55.0 / gainMeanValue;
+//       offset[i] = 42.0 / m_Threshold;
+//       gainRMS = 1.3 / gainMeanValue;
+//       offsetRMS = 2.0 / m_Threshold;
+//     }
+
+//     float W = m_OGcorr * gainRMS * offsetRMS / (gainRMS * gainRMS - offsetRMS * offsetRMS);
+//     float A = 4 * W * W + 1.0;
+//     float x1 = (A - sqrt(A)) / (2.0 * A);
+//     sinfi[i] = sqrt(x1);
+//     cosfi[i] = sqrt(1.0 - x1);
+//     sinfi[i] = sinfi[i] * m_OGcorr / fabs(m_OGcorr);
+//     float S = gainRMS * gainRMS + offsetRMS * offsetRMS;
+//     float D = (gainRMS * gainRMS - offsetRMS * offsetRMS) / (cosfi[i] * cosfi[i] - sinfi[i] * sinfi[i]);
+//     S1[i] = sqrt((S + D) / 2.0);
+//     S2[i] = sqrt((S - D) / 2.0);
+//   }
+
+//   // Loop over collection and setup gain/offset/noise for the hit and neighbouring strips
+//   SiChargedDiodeIterator i_chargedDiode = collection.begin();
+//   SiChargedDiodeIterator i_chargedDiode_end = collection.end();
+
+//   for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
+//     SiChargedDiode diode = (*i_chargedDiode).second;
+//     // should be const as we aren't trying to change it here - but getReadoutCell() is not a const method...
+//     unsigned int flagmask = diode.flag() & 0xFE;
+//     // Get the flag for this diode ( if flagmask = 1 If diode is disconnected/disabled skip it)
+//     if (!flagmask) { // If the diode is OK (not flagged)
+//       const SiReadoutCellId roCell = diode.getReadoutCell();
+
+//       if (roCell.isValid()) {
+//         int strip = roCell.strip();
+//         int i = std::max(strip - 1, 0);
+//         int i_end = std::min(strip + 2, m_strip_max.load());
+
+//         // loop over strips
+//         for (; i < i_end; i++) {
+//           // Need to check if strip is already setup
+//           if (data.m_Analogue[1][i] <= 0.0) {
+//             // Values depends on which chip the strip is on (complex when strip is on chip edge)
+//             int chip = i / 128;
+//             float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S1[chip]);
+//             float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S2[chip]);
+
+//             data.m_GainFactor[i] = gain[chip] + (cosfi[chip] * g + sinfi[chip] * o);
+//             data.m_Offset[i] = offset[chip]   + (cosfi[chip] * o - sinfi[chip] * g);
+//             data.m_NoiseFactor[i] = noiseByChipVect[chip];
+
+//             // Fill the noise and offset values into the Analogue
+//             if (m_data_compression_mode == 1 and m_data_readout_mode == 0) { // level mode x1x
+//               data.m_Analogue[1][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+//             } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) { // edge mode 01x
+//               data.m_Analogue[0][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+//               data.m_Analogue[1][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+//             } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) { // any hit mode xxx or expanded read out mode
+//               data.m_Analogue[0][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+//               data.m_Analogue[1][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+//               data.m_Analogue[2][i] = data.m_Offset[i] + data.m_NoiseFactor[i] * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
+//             }
+//           }
+//         }
+//       }
+//     }
+//   }
+
+//   return StatusCode::SUCCESS;
+// }
+
+// ----------------------------------------------------------------------
+//
+// ----------------------------------------------------------------------
+StatusCode SCT_FrontEnd::randomNoise(SiChargedDiodeCollection& collection, /*const Identifier& moduleId,*/ CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data) const {
+  // Add random noise
+
+  double occupancy = 0.0;
+  double NoiseOccupancy = 0.0;
+  float Noise = 0.0;
+  int nNoisyStrips = 0;
+  double mode = 1.;
+
+  const bool noise_expanded_mode = (m_data_compression_mode == 3 and m_data_readout_mode == 1);
+
+  // Will give 3 times as much noise occupancy if running in any hit expanded mode
+  if (noise_expanded_mode) {
+    mode = 3.;
+  }
+
+  // Sets fixed noise occupancy values for different module types, barrel, EC,
+  // inners, middles
+  // short middles, and outers
+//   if (m_sct_id->barrel_ec(moduleId) == 0) { // barrel_ec=0 corresponds to barrel
+//     if (m_sct_id->layer_disk(moduleId) == 3) { // outer barrel layer 10 degrees warmer
+      NoiseOccupancy = m_NOBarrel3;
+      Noise = m_NoiseBarrel3;
+//     } else {
+//       NoiseOccupancy = m_NOBarrel;
+//       Noise = m_NoiseBarrel;
+//     }
+//   } else {
+//     int moduleType = m_sct_id->eta_module(moduleId);
+//     switch (moduleType) { // eta = 0, 1, or 2 corresponds to outers, middles and inners?! (at least in the offline world)
+//     case 0: {
+//       NoiseOccupancy = m_NOOuters;
+//       Noise = m_NoiseOuters;
+//       break;
+//     }
+//     case 1: {
+//       if (m_sct_id->layer_disk(moduleId) == 7) {
+//         NoiseOccupancy = m_NOShortMiddles;
+//         Noise = m_NoiseShortMiddles;
+//       } else {
+//         NoiseOccupancy = m_NOMiddles;
+//         Noise = m_NoiseMiddles;
+//       }
+//       break;
+//     }
+//     case 2: {
+//       NoiseOccupancy = m_NOInners;
+//       Noise = m_NoiseInners;
+//       break;
+//     }
+//     default: {
+//       NoiseOccupancy = m_NOBarrel;
+//       Noise = m_NoiseBarrel;
+//       ATH_MSG_ERROR("moduleType(eta): " << moduleType << " unknown, using barrel");
+//     }
+//     }// end of switch structure
+//   }
+
+  // Calculate the number of "free strips"
+  int nEmptyStrips = 0;
+  std::vector<int> emptyStrips;
+  emptyStrips.reserve(m_strip_max);
+  for (int i = 0; i < m_strip_max; i++) {
+    if (data.m_StripHitsOnWafer[i] == 0) {
+      emptyStrips.push_back(i);
+      ++nEmptyStrips;
+    }
+  }
+
+  if (nEmptyStrips != 0) {
+    // Should randomize the fixed NO values, so we get some differences per
+    // wafer
+    occupancy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, NoiseOccupancy, NoiseOccupancy * 0.1);
+
+    // Modify the occupancy if threshold is not 1.0 fC
+    if (m_Threshold > 6242.3 or m_Threshold < 6242.1) {
+      const float fC = 6242.2;
+      occupancy = occupancy * exp(-(0.5 / (Noise * Noise) * (m_Threshold * m_Threshold - fC * fC)));
+    }
+    nNoisyStrips = CLHEP::RandPoisson::shoot(rndmEngine, m_strip_max * occupancy * mode);
+
+    // Check and adapt the number of noisy strips to the number of free strips
+    if (nEmptyStrips < nNoisyStrips) {
+      nNoisyStrips = nEmptyStrips;
+    }
+
+    // Find random strips to get noise hits
+    for (int i = 0; i < nNoisyStrips; i++) {
+      int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStrips - i); // strip == 10, 12 free strips
+      // have vector [10000100100200211001] 20 strips
+      int strip = emptyStrips.at(index);
+      emptyStrips.erase(emptyStrips.begin()+index); // Erase it not to use it again
+      if (data.m_StripHitsOnWafer[strip]!=0) {
+        ATH_MSG_ERROR(index << "-th empty strip, strip " << strip << " should be empty but is not empty! Something is wrong!");
+      }
+      data.m_StripHitsOnWafer[strip] = 3; // !< Random Noise hit
+      // Add tbin info to noise diode
+      if (noise_expanded_mode) { // !< if any hit mode, any time bin otherwise fixed tbin=2
+        int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
+        // !< random number 0, 1 or 2
+        if (noise_tbin == 0) {
+          noise_tbin = 4; // !< now 1,2 or 4
+        }
+        if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, noise_tbin)) {
+          ATH_MSG_ERROR("Can't add noise hit diode to collection");
+        }
+      } else {
+        if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
+          ATH_MSG_ERROR("Can't add noise hit diode to collection");
+        }
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+//
+// ----------------------------------------------------------------------
+// StatusCode SCT_FrontEnd::randomNoise(SiChargedDiodeCollection& collection, const Identifier& moduleId, int side, CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data) const {
+//   const int n_chips = 6;
+//   const int chipStripmax = m_strip_max / n_chips;
+//   std::vector<float> NOByChipVect(n_chips, 0.0);
+//   std::vector<float> ENCByChipVect(n_chips, 0.0);
+//   std::vector<int> nNoisyStrips(n_chips, 0);
+//   double mode = 1.;
+
+//   const bool noise_expanded_mode = (m_data_compression_mode == 3 and m_data_readout_mode == 1);
+
+//   // Will give 3 times as much noise occupancy if running in any hit expanded mode
+//   if (noise_expanded_mode) {
+//     mode = 3.;
+//   }
+
+//   // Get chip data from calib DB
+//   NOByChipVect = m_ReadCalibChipDataTool->getNoiseOccupancyData(moduleId, side, "OccupancyByChip");
+//   ENCByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "NoiseByChip");
+
+//   // Need to check if empty, most should have data, but a few old DEAD modules don't, and 9C...
+//   if (NOByChipVect.empty()) {
+//     ATH_MSG_DEBUG("No calibration data in cond DB for module " << moduleId << " using JO values");
+//     if (StatusCode::SUCCESS != randomNoise(collection, moduleId, rndmEngine, data)) {
+//       return StatusCode::FAILURE;
+//     } else {
+//       return StatusCode::SUCCESS;
+//     }
+//   } else {
+//     for (int i = 0; i < n_chips; i++) {
+//       // A 0 value can mean two things now, chip out of config for long time and no value was uploaded
+//       // or its short middles and inners and the value is for all purposes 0! so ok.
+
+//       // Modify the occupancy if threshold is not 1.0 fC
+//       if (m_Threshold > 6242.3 or m_Threshold < 6242.1) {
+//         constexpr float fC = 6242.2;
+//         NOByChipVect[i] = NOByChipVect[i] * exp(-(0.5 / (ENCByChipVect[i]*ENCByChipVect[i]) * (m_Threshold*m_Threshold - fC*fC)));
+//       }
+
+//       nNoisyStrips[i] = CLHEP::RandPoisson::shoot(rndmEngine, chipStripmax * NOByChipVect[i] * mode);
+//     }
+//   }
+
+//   // Loop over the chips on the wafer
+//   for (int chip_index = 0; chip_index < n_chips; ++chip_index) {
+//     int chip_strip_offset = chipStripmax * chip_index; // First strip number on chip
+
+//     // Calculate the number of "free strips" on this chip
+//     int nEmptyStripsOnChip = 0;
+//     std::vector<int> emptyStripsOnChip;
+//     emptyStripsOnChip.reserve(chipStripmax);
+//     for (int i = 0; i < chipStripmax; i++) {
+//       if (data.m_StripHitsOnWafer[i + chip_strip_offset] == 0) {
+//         emptyStripsOnChip.push_back(i);
+//         ++nEmptyStripsOnChip;
+//       }
+//     }
+
+//     // if no empty strips on chip do nothing
+//     if (nEmptyStripsOnChip != 0) {
+//       // Check and adapt the number of noisy strips to the number of free strips
+//       if (nEmptyStripsOnChip < nNoisyStrips[chip_index]) {
+//         nNoisyStrips[chip_index] = nEmptyStripsOnChip;
+//       }
+
+//       // Find random strips to get noise hits
+//       for (int i = 0; i < nNoisyStrips[chip_index]; i++) {
+//         int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStripsOnChip - i);
+//         int strip_on_chip = emptyStripsOnChip.at(index);
+//         emptyStripsOnChip.erase(emptyStripsOnChip.begin()+index); // Erase it not to use it again
+//         int strip = strip_on_chip + chip_strip_offset;
+//         if (data.m_StripHitsOnWafer[strip]!=0) {
+//           ATH_MSG_ERROR(index << "-th empty strip, strip " << strip << " should be empty but is not empty! Something is wrong!");
+//         }
+//         data.m_StripHitsOnWafer[strip] = 3; // !< Random Noise hit
+//         // Add tbin info to noise diode
+//         if (noise_expanded_mode) { // !< if any hit mode, any time bin
+//           // !< otherwise fixed tbin=2
+//           int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
+//           // !< random number 0, 1 or 2
+//           if (noise_tbin == 0) {
+//             noise_tbin = 4; // !< now 1, 2 or 4
+//           }
+//           if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, noise_tbin)) {
+//             ATH_MSG_ERROR("Can't add noise hit diode to collection");
+//           }
+//         } else {
+//           if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
+//             ATH_MSG_ERROR("Can't add noise hit diode to collection");
+//           }
+//         }
+//       }
+//     }
+//   }
+
+//   return StatusCode::SUCCESS;
+// }
+
+// ----------------------------------------------------------------------
+// process the collection of pre digits this will need to go through
+// all single-strip pre-digits calculate the amplifier response add noise
+// (this could be moved elsewhere later) apply threshold do clustering
+// ----------------------------------------------------------------------
+void SCT_FrontEnd::process(SiChargedDiodeCollection& collection, CLHEP::HepRandomEngine * rndmEngine) const {
+  // get SCT module side design and check it
+  const SCT_ModuleSideDesign *p_design = dynamic_cast<const SCT_ModuleSideDesign*>(&(collection.design()));
+
+  if (p_design==nullptr) {
+    return;
+  }
+
+  SCT_FrontEndData data;
+
+  // Check number of strips in design and from manager(max number of strips on any module)
+  // The design value should always be equal or lower than the manager one
+  // However, no resising is now done in case of a lower value
+  const int strip_max = p_design->cells();
+  // Init vectors
+  if (StatusCode::SUCCESS != initVectors(strip_max, data)) {
+    ATH_MSG_ERROR("Can't resize class variable vectors");
+    return;
+  }
+
+  // Contains strip hit info, reset to 0 for each wafer processed
+  data.m_StripHitsOnWafer.assign(m_strip_max, 0);
+
+  // Containes the charge for each bin on each hit strip
+  if (m_data_compression_mode == 1 and m_data_readout_mode == 0) {
+    for (int i = 0; i < m_strip_max; ++i) {
+      data.m_Analogue[1][i] = 0.0;
+    }
+  } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) {
+    for (int i = 0; i < m_strip_max; ++i) {
+      data.m_Analogue[0][i] = 0.0;
+      data.m_Analogue[1][i] = 0.0;
+    }
+  } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) {
+    for (int i = 0; i < m_strip_max; ++i) {
+      data.m_Analogue[0][i] = 0.0;
+      data.m_Analogue[1][i] = 0.0;
+      data.m_Analogue[2][i] = 0.0;
+    }
+  }
+
+  // Get wafer, moduleId and side
+//   Identifier waferId = collection.identify();
+//   Identifier moduleId = m_sct_id->module_id(waferId);
+//   const int side = m_sct_id->side(waferId);
+
+  // Check if collection empty
+  if (not collection.empty()) {
+    // Setup gain/offset/noise to the hit and neighbouring strips
+    if (m_useCalibData) { // Use calib cond DB data
+        ATH_MSG_FATAL("Use of calibration data not supported.");
+    //   if (StatusCode::SUCCESS != prepareGainAndOffset(collection, side, moduleId, rndmEngine, data)) {
+    //     ATH_MSG_ERROR("\tCan't prepare Gain and Offset");
+    //   }
+    } else { // Use JO values
+      if (StatusCode::SUCCESS != prepareGainAndOffset(collection, /*moduleId,*/ rndmEngine, data)) {
+        ATH_MSG_ERROR("\tCan't prepare Gain and Offset");
+      }
+    }
+
+    if (StatusCode::SUCCESS != doSignalChargeForHits(collection, data)) {
+      ATH_MSG_ERROR("\tCan't doSignalChargeForHits");
+    }
+
+    if (StatusCode::SUCCESS != doThresholdCheckForRealHits(collection, data)) {
+      ATH_MSG_ERROR("\tCan't doThresholdCheckForRealHits");
+    }
+
+    if (StatusCode::SUCCESS != doThresholdCheckForCrosstalkHits(collection, data)) {
+      ATH_MSG_ERROR("\tCan't doThresholdCheckForCrosstalkHits");
+    }
+  }
+
+  if (m_NoiseOn) {
+    if (m_useCalibData) { // Check if using DB or not
+        ATH_MSG_FATAL("Use of calibration data not supported.");
+    //   if (StatusCode::SUCCESS != randomNoise(collection, moduleId, side, rndmEngine, data)) {
+    //     ATH_MSG_ERROR("\tCan't do random noise on wafer?!");
+    //   }
+    } else { // Use JO fixed values
+      if (StatusCode::SUCCESS != randomNoise(collection, /*moduleId,*/ rndmEngine, data)) {
+        ATH_MSG_ERROR("\tCan't do random noise on wafer?!");
+      }
+    }
+  }
+
+  // Check for strips above threshold and do clustering
+  if (StatusCode::SUCCESS != doClustering(collection, data)) {
+    ATH_MSG_ERROR("\tCan't cluster the hits?!");
+  }
+}
+
+StatusCode SCT_FrontEnd::doSignalChargeForHits(SiChargedDiodeCollection& collection, SCT_FrontEndData& data) const {
+  typedef SiTotalCharge::list_t list_t;
+
+  // *****************************************************************************
+  // Loop over the diodes (strips ) and for each of them define the total signal
+  // *****************************************************************************
+
+  // set up number of needed bins depending on the compression mode
+  short bin_max = 0;
+  if (m_data_readout_mode == 0) {
+    bin_max = m_data_compression_mode;
+  } else {
+    bin_max = 3;
+  }
+
+  std::vector<float> response(bin_max);
+
+  SiChargedDiodeIterator i_chargedDiode = collection.begin();
+  SiChargedDiodeIterator i_chargedDiode_end = collection.end();
+  for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
+    SiChargedDiode diode = (*i_chargedDiode).second;
+    // should be const as we aren't trying to change it here - but getReadoutCell() is not a const method...
+    unsigned int flagmask = diode.flag() & 0xFE;
+    // Get the flag for this diode ( if flagmask = 1 If diode is disconnected/disabled skip it)
+    if (!flagmask) { // If the diode is OK (not flagged)
+      const SiReadoutCellId roCell = diode.getReadoutCell();
+
+      if (roCell.isValid()) {
+        int strip = roCell.strip();
+
+        const list_t &ChargesOnStrip = diode.totalCharge().chargeComposition();
+
+        if (m_data_compression_mode == 1 and m_data_readout_mode == 0) { // level mode x1x
+          // Amplifier response
+          data.m_Analogue[1][strip] += data.m_GainFactor[strip] * m_sct_amplifier->response(ChargesOnStrip, m_timeOfThreshold);
+
+          // Add Crosstalk signal for neighboring strip
+          response[0] = m_sct_amplifier->crosstalk(ChargesOnStrip, m_timeOfThreshold);
+          if (strip + 1 < m_strip_max) {
+            data.m_Analogue[1][strip + 1] += data.m_GainFactor[strip + 1] * response[0];
+          }
+          if (strip > 0) {
+            data.m_Analogue[1][strip - 1] += data.m_GainFactor[strip - 1] * response[0];
+          }
+        } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) { // edge mode 01x
+          // Amplifier response
+          m_sct_amplifier->response(ChargesOnStrip, m_timeOfThreshold, response);
+          for (short bin = 0; bin < bin_max; ++bin) {
+            data.m_Analogue[bin][strip] += data.m_GainFactor[strip] * response[bin];
+          }
+          // Add Crosstalk signal for neighboring strip
+          m_sct_amplifier->crosstalk(ChargesOnStrip, m_timeOfThreshold, response);
+          for (short bin = 0; bin < bin_max; ++bin) {
+            if (strip + 1 < m_strip_max) {
+              data.m_Analogue[bin][strip + 1] += data.m_GainFactor[strip + 1] * response[bin];
+            }
+            if (strip > 0) {
+              data.m_Analogue[bin][strip - 1] += data.m_GainFactor[strip - 1] * response[bin];
+            }
+          }
+        } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) { // any hit mode xxx or expanded read out mode
+          // Amplifier response
+          m_sct_amplifier->response(ChargesOnStrip, m_timeOfThreshold, response);
+          for (short bin = 0; bin < bin_max; ++bin) {
+            data.m_Analogue[bin][strip] += data.m_GainFactor[strip] * response[bin];
+          }
+          // Add Crosstalk signal for neighboring strip
+          m_sct_amplifier->crosstalk(ChargesOnStrip, m_timeOfThreshold, response);
+          for (short bin = 0; bin < bin_max; ++bin) {
+            if (strip + 1 < m_strip_max) {
+              data.m_Analogue[bin][strip + 1] += data.m_GainFactor[strip + 1] * response[bin];
+            }
+            if (strip > 0) {
+              data.m_Analogue[bin][strip - 1] += data.m_GainFactor[strip - 1] * response[bin];
+            }
+          }
+        }
+      } else { // if roCell not valid
+        ATH_MSG_WARNING("\t Cannot get the cell ");
+      }
+    } else {// If diode is disconnected/disabled skip it
+      ATH_MSG_WARNING("\tDisabled or disconnected diode (strip)");
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode SCT_FrontEnd::doThresholdCheckForRealHits(SiChargedDiodeCollection& collection, SCT_FrontEndData& data) const {
+  // **********************************************************************************
+  // Flag strips below threshold and flag the threshold check into data.m_StripHitsOnWafer
+  // **********************************************************************************
+
+  SiChargedDiodeIterator i_chargedDiode = collection.begin();
+  SiChargedDiodeIterator i_chargedDiode_end = collection.end();
+
+  for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
+    SiChargedDiode& diode = (*i_chargedDiode).second;
+    SiReadoutCellId roCell = diode.getReadoutCell();
+    if (roCell.isValid()) {
+      int strip = roCell.strip();
+      if (strip > -1 and strip < m_strip_max) {
+        if (m_data_compression_mode == 1 and m_data_readout_mode == 0) { // level mode x1x
+          if (data.m_Analogue[1][strip] < m_Threshold) {
+            SiHelper::belowThreshold(diode, true);   // Below strip diode signal threshold
+            data.m_StripHitsOnWafer[strip] = -1;
+          } else if (((0x10 & diode.flag()) == 0x10) or ((0x4 & diode.flag()) == 0x4)) {
+            // previously a crazy strip number could have screwed things up here.
+            data.m_StripHitsOnWafer[strip] = -1;
+          } else {
+            data.m_StripHitsOnWafer[strip] = 1;
+            SiHelper::SetTimeBin(diode, 2, &msg()); // set timebin info
+          }
+        } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) { // edge mode 01x
+          if ((data.m_Analogue[0][strip] >= m_Threshold or data.m_Analogue[1][strip] < m_Threshold)) {
+            SiHelper::belowThreshold(diode, true);   // Below strip diode signal threshold
+            data.m_StripHitsOnWafer[strip] = -1;
+          } else if (((0x10 & diode.flag()) == 0x10) or ((0x4 & diode.flag()) == 0x4)) {
+            // previously a crazy strip number could have screwed things up here.
+            data.m_StripHitsOnWafer[strip] = -1;
+          } else {
+            data.m_StripHitsOnWafer[strip] = 1;
+            SiHelper::SetTimeBin(diode, 2, &msg()); // set timebin info
+          }
+        } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) { // Check hit pattern
+          int have_hit_bin = 0;
+          if (data.m_Analogue[0][strip] >= m_Threshold) {
+            have_hit_bin = 4;
+          }
+          if (data.m_Analogue[1][strip] >= m_Threshold) {
+            have_hit_bin += 2;
+          }
+          if (data.m_Analogue[2][strip] >= m_Threshold) {
+            have_hit_bin += 1;
+          }
+          if (((0x10 & diode.flag()) == 0x10) || ((0x4 & diode.flag()) == 0x4)) {
+            // previously a crazy strip number could have screwed things up here.
+            data.m_StripHitsOnWafer[strip] = -1;
+          } else if (m_data_compression_mode == 1) { // !< level and expanded mode
+            if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
+              data.m_StripHitsOnWafer[strip] = 1;
+              SiHelper::SetTimeBin(diode, have_hit_bin, &msg());
+            } else {
+              SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
+              data.m_StripHitsOnWafer[strip] = -1;
+            }
+          } else if (m_data_compression_mode == 2) { // !< edge and expanded mode
+            if (have_hit_bin == 2 or have_hit_bin == 3) {
+              data.m_StripHitsOnWafer[strip] = 1;
+              SiHelper::SetTimeBin(diode, have_hit_bin, &msg());
+            } else {
+              SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
+              data.m_StripHitsOnWafer[strip] = -1;
+            }
+          } else if (m_data_compression_mode == 3) { // !< any hit mode
+            if (have_hit_bin == 0) {
+              SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
+              data.m_StripHitsOnWafer[strip] = -1;
+            } else {
+              data.m_StripHitsOnWafer[strip] = 1;
+              if (m_data_readout_mode == 1) { // !< check for exp mode or not
+                SiHelper::SetTimeBin(diode, have_hit_bin, &msg());
+              } else {
+                SiHelper::SetTimeBin(diode, 2, &msg());
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+//
+// ----------------------------------------------------------------------
+StatusCode SCT_FrontEnd::doThresholdCheckForCrosstalkHits(SiChargedDiodeCollection& collection, SCT_FrontEndData& data) const {
+  // Check for noise+crosstalk strips above threshold
+  // data.m_StripHitsOnWafer: real hits above threshold == 1 or below/disconnected
+  // == -1
+  // =0 for free strips or strips with charge to be checked (data.m_Analogue[1]!=0)
+  // Set 2 for crosstalk noise hits and -2 for below ones
+
+  for (int strip = 0; strip < m_strip_max; strip++) {
+    // Find strips with data.m_StripHitsOnWafer[strip] == 0
+    if (data.m_StripHitsOnWafer[strip] != 0) { // real hits already checked
+      continue;
+    }
+    if (data.m_Analogue[1][strip] > 0) { // Better way of doing this?!
+                                    // set data.m_StripHitsOnWafer to x in prepareGainAndOffset
+      if (m_data_compression_mode == 1 and m_data_readout_mode == 0) { // level mode x1x
+        if (data.m_Analogue[1][strip] < m_Threshold) {
+          data.m_StripHitsOnWafer[strip] = -2; // Below threshold
+        } else {
+          data.m_StripHitsOnWafer[strip] = 2; // Crosstalk+Noise hit
+          if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
+            ATH_MSG_ERROR("Can't add noise hit diode to collection");
+          }
+        }
+      } else if (m_data_compression_mode == 2 and m_data_readout_mode == 0) { // edge mode 01x
+        if ((data.m_Analogue[0][strip] >= m_Threshold or data.m_Analogue[1][strip] < m_Threshold)) {
+          data.m_StripHitsOnWafer[strip] = -2; // Below threshold
+        } else {
+          data.m_StripHitsOnWafer[strip] = 2; // Crosstalk+Noise hit
+          if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
+            ATH_MSG_ERROR("Can't add noise hit diode to collection");
+          }
+        }
+      } else if (m_data_compression_mode == 3 or m_data_readout_mode == 1) {
+        int have_hit_bin = 0;
+        if (data.m_Analogue[0][strip] >= m_Threshold) {
+          have_hit_bin = 4;
+        }
+        if (data.m_Analogue[1][strip] >= m_Threshold) {
+          have_hit_bin += 2;
+        }
+        if (data.m_Analogue[2][strip] >= m_Threshold) {
+          have_hit_bin += 1;
+        }
+        if (m_data_compression_mode == 1) { // !< level and expanded mode
+          if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
+            data.m_StripHitsOnWafer[strip] = 2; // Crosstalk+Noise hit
+            if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, have_hit_bin)) {
+              ATH_MSG_ERROR("Can't add noise hit diode to collection");
+            }
+          } else {
+            data.m_StripHitsOnWafer[strip] = -2; // Below threshold
+          }
+        } else if (m_data_compression_mode == 2) { // !< edge and expanded mode
+          if (have_hit_bin == 2 or have_hit_bin == 3) {
+            data.m_StripHitsOnWafer[strip] = 2; // Noise hit
+            if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, have_hit_bin)) {
+              ATH_MSG_ERROR("Can't add noise hit diode to collection");
+            }
+          } else {
+            data.m_StripHitsOnWafer[strip] = -2; // Below threshold
+          }
+        } else if (m_data_compression_mode == 3) { // !< any hit mode
+          if (have_hit_bin == 0) {
+            data.m_StripHitsOnWafer[strip] = -2; // Below threshold
+          } else {
+            data.m_StripHitsOnWafer[strip] = 2; // !< Crosstalk+Noise hit
+            if (m_data_readout_mode == 1) { // !< check for exp mode or not
+              if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, have_hit_bin)) {
+                ATH_MSG_ERROR("Can't add noise hit diode to collection");
+              }
+            } else {
+              if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
+                ATH_MSG_ERROR("Can't add noise hit diode to collection");
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode SCT_FrontEnd::doClustering(SiChargedDiodeCollection& collection, SCT_FrontEndData& data) const {
+  // ********************************
+  // now do clustering
+  // ********************************
+  int strip = 0;
+  int clusterSize = 0;
+
+  const SCT_ModuleSideDesign& sctDesign = dynamic_cast<const SCT_ModuleSideDesign&>(collection.design());
+
+  Identifier hitStrip;
+
+  if (m_data_readout_mode == 0) {
+    do {
+      if (data.m_StripHitsOnWafer[strip] > 0) {
+        // ====== First step: Get the cluster size
+        // ===================================================
+        int clusterFirstStrip = strip;
+
+        // Find end of cluster. In multi-row sensors, cluster cannot span rows.
+        int row = sctDesign.row(strip);
+        if (row < 0) {
+          row = 0;
+        }
+
+        int lastStrip1DInRow = 0;
+        for (int i = 0; i < row + 1; ++i) {
+          lastStrip1DInRow += sctDesign.diodesInRow(i);
+        }
+
+        while (strip < lastStrip1DInRow-1 and data.m_StripHitsOnWafer[strip +1] > 0) {
+          ++strip; // !< Find first strip hit and add up the following strips
+        }
+        int clusterLastStrip = strip;
+
+        clusterSize = (clusterLastStrip - clusterFirstStrip) + 1;
+        hitStrip = m_sct_id->strip_id(collection.identify(), clusterFirstStrip);
+        SiChargedDiode& HitDiode = *(collection.find(hitStrip));
+        SiHelper::SetStripNum(HitDiode, clusterSize, &msg());
+                                                                                      
+        SiChargedDiode *PreviousHitDiode = &HitDiode;
+        for (int i = clusterFirstStrip+1; i <= clusterLastStrip; ++i) {
+          hitStrip = m_sct_id->strip_id(collection.identify(), i);
+          SiChargedDiode& HitDiode2 = *(collection.find(hitStrip));
+          SiHelper::ClusterUsed(HitDiode2, true);
+          PreviousHitDiode->setNextInCluster(&HitDiode2);
+          PreviousHitDiode = &HitDiode2;
+        }
+      }
+      ++strip; // !< This is the starting point of the next cluster within this collection
+    } while (strip < m_strip_max);
+  } else {
+    // Expanded read out mode, basically one RDO/strip per cluster
+    // But if consecutively fired strips have the same time bin, those are converted into one cluster.
+    do {
+      clusterSize = 1;
+      if (data.m_StripHitsOnWafer[strip] > 0) {
+        hitStrip = m_sct_id->strip_id(collection.identify(), strip);
+        SiChargedDiode& hitDiode = *(collection.find(hitStrip));
+        int timeBin = SiHelper::GetTimeBin(hitDiode);
+        SiChargedDiode* previousHitDiode = &hitDiode;
+        // Check if consecutively fired strips have the same time bin
+        for (int newStrip=strip+1; newStrip<m_strip_max; newStrip++) {
+          if (not (data.m_StripHitsOnWafer[newStrip]>0)) break;
+          Identifier newHitStrip = m_sct_id->strip_id(collection.identify(), newStrip);
+          SiChargedDiode& newHitDiode = *(collection.find(newHitStrip));
+          if (timeBin!=SiHelper::GetTimeBin(newHitDiode)) break;
+          SiHelper::ClusterUsed(newHitDiode, true);
+          previousHitDiode->setNextInCluster(&newHitDiode);
+          previousHitDiode = &newHitDiode;
+          clusterSize++;
+        }
+        SiHelper::SetStripNum(hitDiode, clusterSize, &msg());
+
+#ifdef SCT_DIG_DEBUG
+        ATH_MSG_DEBUG("RDO Strip = " << strip << ", tbin = " <<
+                      SiHelper::GetTimeBin(hitDiode) <<
+                      ", HitInfo(1=real, 2=crosstalk, 3=noise): " <<
+                      data.m_StripHitsOnWafer[strip]);
+#endif
+      }
+      strip += clusterSize; // If more than one strip fires, those following strips are skipped.
+    } while (strip < m_strip_max);
+  }
+
+  // clusters below threshold, only from pre-digits that existed before no
+  // pure noise clusters below threshold will be made
+  // D. Costanzo. I don't see why we should cluster the strips below
+  // threshold. I'll pass on the info of strips below threshold
+  // to the SDOs. I'll leave the SCT experts the joy to change this if they
+  // don't like what I did or if this requires too much memory/disk
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode SCT_FrontEnd::addNoiseDiode(SiChargedDiodeCollection& collection, int strip, int tbin) const {
+  const SiCellId ndiode(strip); // !< create a new diode
+  const SiCharge noiseCharge(2 * m_Threshold, 0, SiCharge::noise); // !< add some noise to it
+  collection.add(ndiode, noiseCharge); // !< add it to the collection
+
+  // Get the strip back to check
+  const Identifier idstrip = m_sct_id->strip_id(collection.identify(), strip);
+  SiChargedDiode *NoiseDiode = (collection.find(idstrip));
+  if (NoiseDiode == nullptr) {
+    return StatusCode::FAILURE;
+  }
+  SiHelper::SetTimeBin(*NoiseDiode, tbin, &msg()); // set timebin info
+
+  return StatusCode::SUCCESS;
+}
+
+float SCT_FrontEnd::meanValue(std::vector<float>& calibDataVect) const {
+  float mean_value = 0.0;
+  int nData = 0;
+  const unsigned int vec_size = calibDataVect.size();
+
+  for (unsigned int i = 0; i < vec_size; ++i) {
+    if (calibDataVect[i] > 0.1) {
+      mean_value += calibDataVect[i];
+      ++nData;
+    }
+  }
+
+  if (nData == 0) {
+    return -1;
+  } else {
+    return mean_value / nData;
+  }
+}
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.h b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.h
new file mode 100644
index 00000000..03f34b2c
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_FrontEnd.h
@@ -0,0 +1,140 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * Header file for SCT_FrontEnd Class 
+ * @brief simulation of the SCT front-end electronics
+ * working as a SiPreDigitsProcessor
+ * models response of ABCD chip amplifiers to 
+ * collected charges, also does cross-talk, offset
+ * variation and gain variation, in a correlated way
+ * Version 1.0 04.05.2001 Szymon Gadomski
+ * 1.1 07.06.2001 pass amplifier and design as pointers
+ * 1.2, 15/06/2001, compiles with framework and tested
+ * 31.07.2001 changes, constructor now without design
+ * design is only known to process method (from the collection)
+ * 10.08.2001 dedided not to use AlwaysSame flag
+ * Implementation for using it may be provided later
+ * @author Szymon.Gadomski@cern.ch, Awatif.Belymam@cern.ch, Davide.Costanzo@cern.ch,
+ * tgcornel@nikhef.nl, Grant.Gorfine@cern.ch, Paul.Bell@cern.ch, Jorgen.Dalmau@cern.ch,
+ * 23/08/2007 - Kondo.Gnanvo@cern.ch
+ *            - Conversion of the SCT_Front code Al gTool 
+ */
+
+#ifndef FASERSCT_DIGITIZATION_SCT_FRONTEND_H
+#define FASERSCT_DIGITIZATION_SCT_FRONTEND_H
+
+// Inheritance
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "FaserSCT_Digitization/ISCT_FrontEnd.h"
+
+// Athena
+#include "FaserSiDigitization/SiChargedDiodeCollection.h"
+// #include "SCT_ConditionsTools/ISCT_ReadCalibChipDataTool.h"
+
+// Gaudi
+#include "GaudiKernel/ToolHandle.h"
+
+// STL
+#include <atomic>
+#include <mutex>
+#include <vector>
+
+class ISCT_Amp;
+class FaserSCT_ID;
+
+namespace TrackerDD {
+  class SCT_DetectorManager;
+}
+
+namespace CLHEP {
+  class HepRandomEngine;
+}
+/**
+ * @brief simulation of the SCT front-end electronics
+ * working as a SiPreDigitsProcessor
+ * models response of ABCD chip amplifiers to 
+ * collected charges, also does cross-talk, offset
+ * variation and gain variation, in a correlated way
+ */
+
+struct SCT_FrontEndData {
+  std::vector<float> m_Offset; //!< generate offset per channel
+  std::vector<float> m_GainFactor; //!< generate gain per channel  (added to the gain per chip from calib data)
+  std::vector<float> m_NoiseFactor; //!< Kondo: 31/08/07 noise per channel (actually noise per chip from calib data)
+  std::vector<double> m_Analogue[3];  //!< To hold the noise and amplifier response
+  std::vector<int> m_StripHitsOnWafer; //!< Info about which strips are above threshold
+};
+
+class  SCT_FrontEnd : public extends<AthAlgTool, ISCT_FrontEnd> {
+
+ public:
+
+  /**  constructor */
+  SCT_FrontEnd(const std::string& type, const std::string& name, const IInterface* parent);
+  /** Destructor */
+  virtual ~SCT_FrontEnd() = default;
+  //PJ not needed after merging?!
+  /** AlgTool InterfaceID */
+  //static const InterfaceID& interfaceID();
+  
+  /** AlgTool initialize */
+  virtual StatusCode initialize() override;
+  /** AlgTool finalize */
+  virtual StatusCode finalize() override;
+
+  /**
+   * process the collection of pre digits: needed to go through all single-strip pre-digits to calculate
+   * the amplifier response add noise (this could be moved elsewhere later) apply threshold do clustering
+   */
+  virtual void process(SiChargedDiodeCollection& collection, CLHEP::HepRandomEngine* rndmEngine) const override;
+  StatusCode doSignalChargeForHits(SiChargedDiodeCollection& collectione, SCT_FrontEndData& data) const;
+  StatusCode doThresholdCheckForRealHits(SiChargedDiodeCollection& collectione, SCT_FrontEndData& data) const;
+  StatusCode doThresholdCheckForCrosstalkHits(SiChargedDiodeCollection& collection, SCT_FrontEndData& data) const;
+  StatusCode doClustering(SiChargedDiodeCollection& collection, SCT_FrontEndData& data) const;
+  StatusCode prepareGainAndOffset(SiChargedDiodeCollection& collection, /*const Identifier& moduleId,*/ CLHEP::HepRandomEngine* rndmEngine, SCT_FrontEndData& data) const;
+//   StatusCode prepareGainAndOffset(SiChargedDiodeCollection& collection, int side, const Identifier& moduleId, CLHEP::HepRandomEngine* rndmEngine, SCT_FrontEndData& data) const;
+  StatusCode randomNoise(SiChargedDiodeCollection& collection, /*const Identifier& moduleId,*/ CLHEP::HepRandomEngine* rndmEngine, SCT_FrontEndData& data) const;
+//   StatusCode randomNoise(SiChargedDiodeCollection& collection, const Identifier& moduleId, int side, CLHEP::HepRandomEngine* rndmEngine, SCT_FrontEndData& data) const;
+  StatusCode addNoiseDiode(SiChargedDiodeCollection& collection, int strip, int tbin) const;
+  float meanValue(std::vector<float>& calibDataVect) const;
+  StatusCode initVectors(int strips, SCT_FrontEndData& data) const;
+
+ private:
+
+  FloatProperty m_NoiseBarrel{this, "NoiseBarrel", 1500.0, "Noise factor, Barrel  (in the case of no use of calibration data)"};
+  FloatProperty m_NoiseBarrel3{this, "NoiseBarrel3", 1541.0, "Noise factor, Barrel3  (in the case of no use of calibration data)"};
+  FloatProperty m_NoiseInners{this, "NoiseInners", 1090.0, "Noise factor, EC Inners  (in the case of no use of calibration data)"};
+  FloatProperty m_NoiseMiddles{this, "NoiseMiddles", 1557.0, "Noise factor, EC Middles (in the case of no use of calibration data)"};
+  FloatProperty m_NoiseShortMiddles{this, "NoiseShortMiddles", 940.0, "Noise factor, EC Short Middles (in the case of no use of calibration data)"};
+  FloatProperty m_NoiseOuters{this, "NoiseOuters", 1618.0, "Noise factor, Ec Outers  (in the case of no use of calibration data)"};
+  DoubleProperty m_NOBarrel{this, "NOBarrel", 1.5e-5, "Noise factor, Barrel  (in the case of no use of calibration data)"};
+  DoubleProperty m_NOBarrel3{this, "NOBarrel3", 2.1e-5, "Noise factor, Barrel3  (in the case of no use of calibration data)"};
+  DoubleProperty m_NOInners{this, "NOInners", 5.0e-9, "Noise Occupancy, EC Inners  (in the case of no use of calibration data)"};
+  DoubleProperty m_NOMiddles{this, "NOMiddles", 2.7e-5, "Noise Occupancy, EC Middles (in the case of no use of calibration data)"};
+  DoubleProperty m_NOShortMiddles{this, "NOShortMiddles", 2.0e-9, "Noise Occupancy, EC Short Middles (in the case of no use of calibration data)"};
+  DoubleProperty m_NOOuters{this, "NOOuters", 3.5e-5, "Noise Occupancy, Ec Outers  (in the case of no use of calibration data)"};
+  BooleanProperty m_NoiseOn{this, "NoiseOn", true, "To know if noise is on or off when using calibration data"};
+  BooleanProperty m_analogueNoiseOn{this, "AnalogueNoiseOn", true, "To know if analogue noise is on or off"};
+  FloatProperty m_GainRMS{this, "GainRMS", 0.031, "Gain spread parameter within the strips for a given Chip gain"};
+  FloatProperty m_Ospread{this, "Ospread", 0.0001, "offset spread within the strips for a given Chip offset"};
+  FloatProperty m_OGcorr{this, "OffsetGainCorrelation", 0.00001, "Gain/offset correlation for the strips"};
+  FloatProperty m_Threshold{this, "Threshold", 1.0, "Threshold"};
+  FloatProperty m_timeOfThreshold{this, "TimeOfThreshold", 30.0, "Threshold time"};
+  ShortProperty m_data_compression_mode{this, "DataCompressionMode", 1, "Front End Data Compression Mode"};
+  ShortProperty m_data_readout_mode{this, "DataReadOutMode", 0, "Front End Data Read out mode Mode"};
+  BooleanProperty m_useCalibData{this, "UseCalibData", false, "Flag to set the use of calibration data for noise, Gain,offset etc."}; // was true in ATLAS
+
+  ToolHandle<ISCT_Amp> m_sct_amplifier{this, "SCT_Amp", "SCT_Amp", "Handle the Amplifier tool"}; //!< Handle the Amplifier tool
+//   ToolHandle<ISCT_ReadCalibChipDataTool> m_ReadCalibChipDataTool{this, "SCT_ReadCalibChipDataTool", "SCT_ReadCalibChipDataTool", "Tool to retrieve chip calibration information"}; //!< Handle to the Calibration ConditionsTool
+
+  const TrackerDD::SCT_DetectorManager* m_SCTdetMgr{nullptr}; //!< Handle to SCT detector manager
+  const FaserSCT_ID* m_sct_id{nullptr}; //!< Handle to SCT ID helper
+
+  mutable std::atomic_int m_strip_max{768}; //!< For SLHC studies
+};
+
+#endif //SCT_FRONTEND_H
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.cxx b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.cxx
new file mode 100644
index 00000000..b170bd10
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.cxx
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "SCT_RandomDisabledCellGenerator.h"
+
+#include "FaserSiDigitization/SiChargedDiodeCollection.h"
+
+#include "FaserSiDigitization/SiHelper.h"
+
+#include "CLHEP/Random/RandomEngine.h"
+#include "CLHEP/Random/RandFlat.h"
+
+// constructor
+SCT_RandomDisabledCellGenerator::SCT_RandomDisabledCellGenerator(const std::string& type, const std::string& name, const IInterface* parent)
+  : base_class(type, name, parent)
+{
+}
+
+StatusCode SCT_RandomDisabledCellGenerator::initialize() {
+  ATH_MSG_DEBUG("SCT_RandomDisabledCellGenerator::initialize()");
+  ATH_MSG_INFO("\tCreating missing bond generator with "<<m_disableProbability<<" probability");
+  return StatusCode::SUCCESS;
+}
+
+StatusCode SCT_RandomDisabledCellGenerator::finalize() {
+  ATH_MSG_INFO("SCT_RandomDisabledCellGenerator::finalize()");
+  return StatusCode::SUCCESS;
+}
+
+// process the collection 
+void SCT_RandomDisabledCellGenerator::process(SiChargedDiodeCollection& collection, CLHEP::HepRandomEngine * rndmEngine) const {
+  // disabling is applied to all cells even unconnected or below threshold ones to be able to use these cells as well
+  // loop on all charged diodes
+  for (std::pair<const TrackerDD::SiCellId, SiChargedDiode>& chargedDiode: collection) {
+    if (CLHEP::RandFlat::shoot(rndmEngine)<m_disableProbability) {
+      SiHelper::disconnected(chargedDiode.second, true, false);
+    }
+  }
+}
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.h b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.h
new file mode 100644
index 00000000..1ea27123
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_RandomDisabledCellGenerator.h
@@ -0,0 +1,67 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// SCT_RandomDisabledCellGenerator.h
+//   Header file for class SCT_RandomDisabledCellGenerator 
+///////////////////////////////////////////////////////////////////
+// Class to randomly disable cells for SCT
+///////////////////////////////////////////////////////////////////
+// Version 1.0 25/07/2007 Kondo Gnanvo
+//   - Randomly select a cell and modify its flag by using the pointer to 
+//     a SiHelper function.
+//   - Inherits from ISiChargedDiodeProcessor, as SiPreDiodeProcessor
+//     has been discontinued
+// This can be used for disabling, disconnecting, and flagging bad_tot
+///////////////////////////////////////////////////////////////////
+
+#ifndef FASERSCT_DIGITIZATION_SCT_RANDOMDISABLEDCELLGENERATOR_H
+#define FASERSCT_DIGITIZATION_SCT_RANDOMDISABLEDCELLGENERATOR_H
+
+//Inheritance
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "FaserSCT_Digitization/ISCT_RandomDisabledCellGenerator.h"
+
+class SiChargedDiode;
+class SiChargedDiodeCollection;
+
+namespace CLHEP {
+  class HepRandomEngine;
+}
+
+class SCT_RandomDisabledCellGenerator : public extends<AthAlgTool, ISCT_RandomDisabledCellGenerator> {
+
+  ///////////////////////////////////////////////////////////////////
+  // Public methods:
+  ///////////////////////////////////////////////////////////////////
+
+ public:
+
+  /**  constructor */
+  SCT_RandomDisabledCellGenerator(const std::string& type, const std::string& name, const IInterface* parent) ;
+
+  /** Destructor */
+  virtual ~SCT_RandomDisabledCellGenerator() = default;
+
+  /** AlgTool initialize */
+  virtual StatusCode initialize() override;
+  /** AlgTool finalize */
+  virtual StatusCode finalize() override;
+
+  virtual void process(SiChargedDiodeCollection& collection, CLHEP::HepRandomEngine * rndmEngine) const override;
+
+ private:
+
+  ///////////////////////////////////////////////////////////////////
+  // Private data:
+  ///////////////////////////////////////////////////////////////////
+ private:
+
+  FloatProperty m_disableProbability{this, "TotalBadChannels", 0.01, "probability that a cell is disabled"};
+
+};
+
+#endif //FASERSCT_DIGITIZATION_SCT_RANDOMDISABLEDCELLGENERATOR_H
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx
new file mode 100644
index 00000000..b05cd7b4
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx
@@ -0,0 +1,578 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "SCT_SurfaceChargesGenerator.h"
+
+// DD
+#include "TrackerReadoutGeometry/SiDetectorElement.h"
+#include "TrackerReadoutGeometry/SCT_ModuleSideDesign.h"
+
+// Athena
+#include "GeneratorObjects/HepMcParticleLink.h"
+#include "TrackerSimEvent/FaserSiHit.h" // for SiHit, SiHit::::xDep, etc
+#include "HitManagement/TimedHitPtr.h" // for TimedHitPtr
+
+// ROOT
+#include "TH1.h" // for TH1F
+#include "TH2.h" // for TH2F
+#include "TProfile.h" // for TProfile
+
+// CLHEP
+#include "CLHEP/Geometry/Point3D.h"
+#include "CLHEP/Random/RandomEngine.h"
+#include "CLHEP/Random/RandGaussZiggurat.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+// STL
+#include <cmath>
+
+using TrackerDD::SiDetectorElement;
+using TrackerDD::SCT_ModuleSideDesign;
+using TrackerDD::SiLocalPosition;
+
+using namespace std;
+
+// constructor
+SCT_SurfaceChargesGenerator::SCT_SurfaceChargesGenerator(const std::string& type,
+                                                         const std::string& name,
+                                                         const IInterface* parent)
+  : base_class(type, name, parent) {
+}
+
+// ----------------------------------------------------------------------
+// Initialize
+// ----------------------------------------------------------------------
+StatusCode SCT_SurfaceChargesGenerator::initialize() {
+  ATH_MSG_DEBUG("SCT_SurfaceChargesGenerator::initialize()");
+
+  // Get ISiPropertiesTool
+  ATH_CHECK(m_siPropertiesTool.retrieve());
+
+  // Get ISiliconConditionsSvc
+//   ATH_CHECK(m_siConditionsTool.retrieve());
+
+  if (m_doTrapping) {
+    // -- Get Radiation Damage Tool
+    ATH_MSG_FATAL("Radiation damage tool not supported.");
+//     ATH_CHECK(m_radDamageTool.retrieve());
+//   } else {
+//     m_radDamageTool.disable();
+  }
+
+//   if (m_doHistoTrap) {
+//     // -- Get Histogram Service
+//     ATH_CHECK(m_thistSvc.retrieve());
+
+//     m_h_efieldz = new TProfile("efieldz", "", 50, 0., 0.4);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/efieldz", m_h_efieldz));
+
+//     m_h_efield = new TH1F("efield", "", 100, 200., 800.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/efield", m_h_efield));
+
+//     m_h_spess = new TH1F("spess", "", 50, 0., 0.4);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/spess", m_h_spess));
+
+//     m_h_depD = new TH1F("depD", "", 50, -0.3, 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/depD", m_h_depD));
+
+//     m_h_drift_electrode = new TH2F("drift_electrode", "", 50, 0., 20., 50, 0., 20.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/drift_electrode", m_h_drift_electrode));
+
+//     m_h_drift_time = new TH1F("drift_time", "", 100, 0., 20.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/drift_time", m_h_drift_time));
+
+//     m_h_t_electrode = new TH1F("t_electrode", "", 100, 0., 20.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/t_electrode", m_h_t_electrode));
+
+//     m_h_ztrap = new TH1F("ztrap", "", 100, 0., 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/ztrap", m_h_ztrap));
+
+//     // More histograms to check what's going on
+//     m_h_zhit = new TH1F("zhit", "", 50, -0.2, 0.2);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/zhit", m_h_zhit));
+
+//     m_h_ztrap_tot = new TH1F("ztrap_tot", "", 100, 0., 0.5);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/ztrap_tot", m_h_ztrap_tot));
+
+//     m_h_no_ztrap = new TH1F("no_ztrap", "", 100, 0., 0.5);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/no_ztrap", m_h_no_ztrap));
+
+//     m_h_trap_drift_t = new TH1F("trap_drift_t", "", 100, 0., 20.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/trap_drift_t", m_h_trap_drift_t));
+
+//     m_h_notrap_drift_t = new TH1F("notrap_drift_t", "", 100, 0., 20.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/notrap_drift_t", m_h_notrap_drift_t));
+
+//     m_h_mob_Char = new TProfile("mob_Char", "", 200, 100., 1000.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/mob_Char", m_h_mob_Char));
+
+//     m_h_vel = new TProfile("vel", "", 100, 100., 1000.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/vel", m_h_vel));
+
+//     m_h_drift1 = new TProfile("drift1", "", 50, 0., 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/drift1", m_h_drift1));
+
+//     m_h_gen = new TProfile("gen", "", 50, 0., 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/gen", m_h_gen));
+
+//     m_h_gen1 = new TProfile("gen1", "", 50, 0., 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/gen1", m_h_gen1));
+
+//     m_h_gen2 = new TProfile("gen2", "", 50, 0., 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/gen2", m_h_gen2));
+
+//     m_h_velocity_trap = new TProfile("velocity_trap", "", 50, 0., 1000.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/velocity_trap", m_h_velocity_trap));
+
+//     m_h_mobility_trap = new TProfile("mobility_trap", "", 50, 100., 1000.);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/mobility_trap", m_h_mobility_trap));
+
+//     m_h_trap_pos = new TH1F("trap_pos", "", 100, 0., 0.3);
+//     ATH_CHECK(m_thistSvc->regHist("/file1/trap_pos", m_h_trap_pos));
+//   }
+  ///////////////////////////////////////////////////
+
+  m_smallStepLength.setValue(m_smallStepLength.value() * CLHEP::micrometer);
+  m_tSurfaceDrift.setValue(m_tSurfaceDrift.value() * CLHEP::ns);
+
+  // Surface drift time calculation Stuff
+  m_tHalfwayDrift = m_tSurfaceDrift * 0.5;
+  m_distHalfInterStrip = m_distInterStrip * 0.5;
+  if ((m_tSurfaceDrift > m_tHalfwayDrift) and (m_tHalfwayDrift >= 0.0) and
+      (m_distHalfInterStrip > 0.0) and (m_distHalfInterStrip < m_distInterStrip)) {
+    m_SurfaceDriftFlag = true;
+  } else {
+    ATH_MSG_INFO("\tsurface drift still not on, wrong params");
+  }
+
+  // Make sure these two flags are not set simultaneously
+  if (m_tfix>-998. and m_tsubtract>-998.) {
+    ATH_MSG_FATAL("\tCannot set both FixedTime and SubtractTime options!");
+    ATH_MSG_INFO("\tMake sure the two flags are not set simultaneously in jo");
+    return StatusCode::FAILURE;
+  }
+
+  if (m_doDistortions) {
+      ATH_MSG_FATAL("Distortions not supported.");
+//     ATH_CHECK(m_distortionsTool.retrieve());
+//   } else {
+//     m_distortionsTool.disable();
+  }
+
+  ATH_CHECK(m_lorentzAngleTool.retrieve());
+
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+// finalize
+// ----------------------------------------------------------------------
+StatusCode SCT_SurfaceChargesGenerator::finalize() {
+  ATH_MSG_DEBUG("SCT_SurfaceChargesGenerator::finalize()");
+  return StatusCode::SUCCESS;
+}
+
+// ----------------------------------------------------------------------
+// perpandicular Drift time calculation
+// ----------------------------------------------------------------------
+float SCT_SurfaceChargesGenerator::driftTime(float zhit, const SiDetectorElement* element) const {
+  if (element==nullptr) {
+    ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process element is nullptr");
+    return -2.0;
+  }
+  const SCT_ModuleSideDesign* design{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))};
+  if (design==nullptr) {
+    ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process can not get " << design);
+    return -2.0;
+  }
+  const double thickness{design->thickness()};
+  const IdentifierHash hashId{element->identifyHash()};
+
+  if ((zhit < 0.0) or (zhit > thickness)) {
+    ATH_MSG_DEBUG("driftTime: hit coordinate zhit=" << zhit / CLHEP::micrometer << " out of range");
+    return -2.0;
+  }
+
+  float depletionVoltage{0.};
+  float biasVoltage{0.};
+  if (m_useSiCondDB) {
+      ATH_MSG_FATAL("Conditions DB voltages not supported.");
+    // depletionVoltage = m_siConditionsTool->depletionVoltage(hashId) * CLHEP::volt;
+    // biasVoltage = m_siConditionsTool->biasVoltage(hashId) * CLHEP::volt;
+  } else {
+    depletionVoltage = m_vdepl * CLHEP::volt;
+    biasVoltage = m_vbias * CLHEP::volt;
+  }
+
+  const float denominator{static_cast<float>(depletionVoltage + biasVoltage - (2.0 * zhit * depletionVoltage / thickness))};
+  if (denominator <= 0.0) {
+    if (biasVoltage >= depletionVoltage) { // Should not happen
+      if(not m_isOverlay) {
+        ATH_MSG_ERROR("driftTime: negative argument X for log(X) " << zhit);
+      }
+      return -1.0;
+    } else { 
+      // (m_biasVoltage<m_depletionVoltage) can happen with underdepleted sensors, lose charges in that volume
+      return -10.0;
+    }
+  }
+
+  float t_drift{log((depletionVoltage + biasVoltage) / denominator)};
+  t_drift *= thickness * thickness / (2.0 * m_siPropertiesTool->getSiProperties(hashId).holeDriftMobility() * depletionVoltage);
+  return t_drift;
+}
+
+// ----------------------------------------------------------------------
+// Sigma diffusion calculation
+// ----------------------------------------------------------------------
+float SCT_SurfaceChargesGenerator::diffusionSigma(float zhit, const SiDetectorElement* element) const {
+  if (element==nullptr) {
+    ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::diffusionSigma element is nullptr");
+    return 0.0;
+  }
+  const IdentifierHash hashId{element->identifyHash()};
+  const float t{driftTime(zhit, element)}; // in ns
+
+  if (t > 0.0) {
+    const float sigma{static_cast<float>(sqrt(2. * m_siPropertiesTool->getSiProperties(hashId).holeDiffusionConstant() * t))}; // in mm
+    return sigma;
+  } else {
+    return 0.0;
+  }
+}
+
+// ----------------------------------------------------------------------
+// Maximum drift time
+// ----------------------------------------------------------------------
+float SCT_SurfaceChargesGenerator::maxDriftTime(const SiDetectorElement* element) const {
+  if (element) {
+    const float sensorThickness{static_cast<float>(element->thickness())};
+    return driftTime(sensorThickness, element);
+  } else {
+    ATH_MSG_INFO("Error: SiDetectorElement not set!");
+    return 0.;
+  }
+}
+
+// ----------------------------------------------------------------------
+// Maximum Sigma difusion
+// ----------------------------------------------------------------------
+float SCT_SurfaceChargesGenerator::maxDiffusionSigma(const SiDetectorElement* element) const {
+  if (element) {
+    const float sensorThickness{static_cast<float>(element->thickness())};
+    return diffusionSigma(sensorThickness, element);
+  } else {
+    ATH_MSG_INFO("Error: SiDetectorElement not set!");
+    return 0.;
+  }
+}
+
+// ----------------------------------------------------------------------
+// Calculating the surface drift time but I should confess that
+// I haven't found out yet where the calculation come from
+// ----------------------------------------------------------------------
+float SCT_SurfaceChargesGenerator::surfaceDriftTime(float ysurf) const {
+  if (m_SurfaceDriftFlag) {
+    if ((ysurf >= 0.0) and (ysurf <= m_distInterStrip)) {
+      float t_surfaceDrift{0.};
+      if (ysurf < m_distHalfInterStrip) {
+        const float y{ysurf / m_distHalfInterStrip};
+        t_surfaceDrift= m_tHalfwayDrift * y * y;
+      } else {
+        const float y{(m_distInterStrip - ysurf) / (m_distInterStrip - m_distHalfInterStrip)};
+        t_surfaceDrift = m_tSurfaceDrift + (m_tHalfwayDrift - m_tSurfaceDrift) * y * y;
+      }
+      return t_surfaceDrift;
+    } else {
+      ATH_MSG_INFO(" ysurf out of range " << ysurf);
+      return -1.0;
+    }
+  } else {
+    return 0.0;
+  }
+}
+
+// -------------------------------------------------------------------------------------------
+// create a list of surface charges from a hit - called from SCT_Digitization
+// AthAlgorithm
+// -------------------------------------------------------------------------------------------
+void SCT_SurfaceChargesGenerator::process(const SiDetectorElement* element,
+                                          const TimedHitPtr<FaserSiHit>& phit,
+                                          const ISiSurfaceChargesInserter& inserter, CLHEP::HepRandomEngine * rndmEngine) const {
+  ATH_MSG_VERBOSE("SCT_SurfaceChargesGenerator::process starts");
+  processSiHit(element, *phit, inserter, phit.eventTime(), phit.eventId(), rndmEngine);
+  return;
+}
+
+// -------------------------------------------------------------------------------------------
+// create a list of surface charges from a hit - called from both AthAlgorithm
+// and PileUpTool
+// -------------------------------------------------------------------------------------------
+void SCT_SurfaceChargesGenerator::processSiHit(const SiDetectorElement* element,
+                                               const FaserSiHit& phit,
+                                               const ISiSurfaceChargesInserter& inserter,
+                                               float p_eventTime,
+                                               unsigned short p_eventId, CLHEP::HepRandomEngine * rndmEngine) const {
+  const SCT_ModuleSideDesign* design{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))};
+  if (design==nullptr) {
+    ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process can not get " << design);
+    return;
+  }
+
+  const double thickness{design->thickness()};
+  const IdentifierHash hashId{element->identifyHash()};
+  const double tanLorentz{m_lorentzAngleTool->getTanLorentzAngle(hashId)};
+
+  // ---**************************************
+  //  Time of Flight Calculation - separate method?
+  // ---**************************************
+  // --- Original calculation of Time of Flight of the particle Time needed by the particle to reach the sensor
+  float timeOfFlight{p_eventTime + hitTime(phit)};
+
+  // Kondo 19/09/2007: Use the coordinate of the center of the module to calculate the time of flight
+  timeOfFlight -= (element->center().mag()) / CLHEP::c_light;
+  // !< extract the distance to the origin of the module to Time of flight
+
+  // !< timing set from jo to adjust (subtract) the timing
+  if (m_tsubtract > -998.) {
+    timeOfFlight -= m_tsubtract;
+  }
+  // ---**************************************
+
+  const CLHEP::Hep3Vector pos{phit.localStartPosition()};
+  const float xEta{static_cast<float>(pos[FaserSiHit::xEta])};
+  const float xPhi{static_cast<float>(pos[FaserSiHit::xPhi])};
+  const float xDep{static_cast<float>(pos[FaserSiHit::xDep])};
+
+  const CLHEP::Hep3Vector endPos{phit.localEndPosition()};
+  const float cEta{static_cast<float>(endPos[FaserSiHit::xEta]) - xEta};
+  const float cPhi{static_cast<float>(endPos[FaserSiHit::xPhi]) - xPhi};
+  const float cDep{static_cast<float>(endPos[FaserSiHit::xDep]) - xDep};
+
+  const float LargeStep{sqrt(cEta*cEta + cPhi*cPhi + cDep*cDep)};
+  const int numberOfSteps{static_cast<int>(LargeStep / m_smallStepLength) + 1};
+  const float steps{static_cast<float>(m_numberOfCharges * numberOfSteps)};
+  const float e1{static_cast<float>(phit.energyLoss() / steps)};
+  const float q1{static_cast<float>(e1 * m_siPropertiesTool->getSiProperties(hashId).electronHolePairsPerEnergy())};
+
+  // in the following, to test the code, we will use the original coordinate
+  // system of the SCTtest3SurfaceChargesGenerator x is eta y is phi z is depth
+  float xhit{xEta};
+  float yhit{xPhi};
+  float zhit{xDep};
+
+  if (m_doDistortions) {
+      ATH_MSG_FATAL("Distortions not supported.");
+    // if (element->isBarrel()) {// Only apply disortions to barrel modules
+    //   Amg::Vector2D BOW;
+    //   BOW[0] = m_distortionsTool->correctSimulation(hashId, xhit, yhit, cEta, cPhi, cDep)[0];
+    //   BOW[1] = m_distortionsTool->correctSimulation(hashId, xhit, yhit, cEta, cPhi, cDep)[1];
+    //   xhit = BOW.x();
+    //   yhit = BOW.y();
+    // }
+  }
+
+  const float StepX{cEta / numberOfSteps};
+  const float StepY{cPhi / numberOfSteps};
+  const float StepZ{cDep / numberOfSteps};
+  
+  // check the status of truth information for this SiHit
+  // some Truth information is cut for pile up events
+  const HepMcParticleLink trklink{HepMcParticleLink(phit.trackNumber(), p_eventId)};
+  SiCharge::Process hitproc{SiCharge::track};
+  if (phit.trackNumber() != 0) {
+    if (not trklink.isValid()) {
+      hitproc = SiCharge::cut_track;
+    }
+  }
+
+  float dstep{-0.5};
+  for (int istep{0}; istep < numberOfSteps; ++istep) {
+    dstep += 1.0;
+    float z1{zhit + StepZ * dstep};
+
+    // Distance between charge and readout side.
+    // design->readoutSide() is +1 if readout side is in +ve depth axis direction and visa-versa.
+    float zReadout{static_cast<float>(0.5 * thickness - design->readoutSide() * z1)};
+    // const double spess{zReadout};
+
+    // if (m_doHistoTrap) {
+    //   m_h_depD->Fill(z1);
+    //   m_h_spess->Fill(spess);
+    // }
+
+    float t_drift{driftTime(zReadout, element)};  // !< t_drift: perpandicular drift time
+    if (t_drift>-2.0000002 and t_drift<-1.9999998) {
+      ATH_MSG_DEBUG("Checking for rounding errors in compression");
+      if ((fabs(z1) - 0.5 * thickness) < 0.000010) {
+        ATH_MSG_DEBUG("Rounding error found attempting to correct it. z1 = " << std::fixed << std::setprecision(8) << z1);
+        if (z1 < 0.0) {
+          z1 = 0.0000005 - 0.5 * thickness;
+          // set new coordinate to be 0.5nm inside wafer volume.
+        } else {
+          z1 = 0.5 * thickness - 0.0000005;
+          // set new coordinate to be 0.5nm inside wafer volume.
+        }
+        zReadout = 0.5 * thickness - design->readoutSide() * z1;
+        t_drift = driftTime(zReadout, element);
+        if (t_drift>-2.0000002 and t_drift<-1.9999998) {
+          ATH_MSG_WARNING("Attempt failed. Making no correction.");
+        } else {
+          ATH_MSG_DEBUG("Correction Successful! z1 = " << std::fixed << std::setprecision(8) << z1 << ", zReadout = " << zReadout << ", t_drift = " << t_drift);
+        }
+      } else {
+        ATH_MSG_DEBUG("No rounding error found. Making no correction.");
+      }
+    }
+    if (t_drift > 0.0) {
+      const float x1{xhit + StepX * dstep};
+      float y1{yhit + StepY * dstep};
+      y1 += tanLorentz * zReadout; // !< Taking into account the magnetic field
+      const float sigma{diffusionSigma(zReadout, element)};
+
+      for (int i{0}; i < m_numberOfCharges; ++i) {
+        const float rx{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
+        const float xd{x1 + sigma * rx};
+        const float ry{CLHEP::RandGaussZiggurat::shoot(rndmEngine)};
+        const float yd{y1 + sigma * ry};
+
+        // For charge trapping with Ramo potential
+        const double stripPitch{0.080}; // mm
+        double dstrip{y1 / stripPitch}; // mm
+        if (dstrip > 0.) {
+          dstrip -= static_cast<double>(static_cast<int>(dstrip));
+        } else {
+          dstrip -= static_cast<double>(static_cast<int>(dstrip)) + 1;
+        }
+
+        // now y will be x and z will be y ....just to make sure to confuse everebody
+        // double y0{dstrip * stripPitch}; // mm
+        // double z0{thickness - zReadout}; // mm
+
+        // -- Charge Trapping
+        // if (m_doTrapping) {
+        //   if (m_doHistoTrap) {
+        //     m_h_zhit->Fill(zhit);
+        //   }
+        //   double trap_pos{-999999.}, drift_time{-999999.}; // FIXME need better default values
+        //   if (chargeIsTrapped(spess, element, trap_pos, drift_time)) {
+        //     if (not m_doRamo) {
+        //       break;
+        //     } else {  // if we want to take into account also Ramo Potential
+        //       double Q_m2{0.}, Q_m1{0.}, Q_00{0.}, Q_p1{0.}, Q_p2{0.}; // Charges
+
+        //       dstrip = y1 / stripPitch; // mm
+        //       // need the distance from the nearest strips
+        //       // edge not centre, xtaka = 1/2*stripPitch
+        //       // centre of detector, y1=0, is in the middle of
+        //       // an interstrip gap
+        //       if (dstrip > 0.) {
+        //         dstrip -= static_cast<double>(static_cast<int>(dstrip));
+        //       } else {
+        //         dstrip -= static_cast<double>(static_cast<int>(dstrip)) + 1;
+        //       }
+
+        //       // now y will be x and z will be y ....just to make sure to confuse everebody
+        //       double yfin{dstrip * stripPitch}; // mm
+        //       double zfin{thickness - trap_pos}; // mm
+
+        //       m_radDamageTool->holeTransport(y0, z0, yfin, zfin, Q_m2, Q_m1, Q_00, Q_p1, Q_p2);
+        //       for (int strip{-2}; strip<=2; strip++) {
+        //         const double ystrip{yd + strip * stripPitch}; // mm
+        //         const SiLocalPosition position(element->hitLocalToLocal(xd, ystrip));
+        //         if (design->inActiveArea(position)) {
+        //           double charge{0.};
+        //           if (strip == -2) charge = Q_m2;
+        //           if (strip == -1) charge = Q_m1;
+        //           if (strip ==  0) charge = Q_00;
+        //           if (strip ==  1) charge = Q_p1;
+        //           if (strip ==  2) charge = Q_p2;
+        //           const double time{drift_time};
+        //           if (charge != 0.) {
+        //             inserter(SiSurfaceCharge(position, SiCharge(q1*charge, time, hitproc, trklink)));
+        //             continue;
+        //           }
+        //         }
+        //       }
+        //       ATH_MSG_INFO("strip zero charge = " << Q_00); // debug
+        //     } // m_doRamo==true
+        //   } // chargeIsTrapped()
+        // } // m_doTrapping==true
+        
+        if (not m_doRamo) {
+          const SiLocalPosition position{element->hitLocalToLocal(xd, yd)};
+          if (design->inActiveArea(position)) {
+            const float sdist{static_cast<float>(design->scaledDistanceToNearestDiode(position))}; // !< dist on the surface from the hit point to the nearest strip (diode)
+            const float t_surf{surfaceDriftTime(2.0 * sdist)}; // !< Surface drift time
+            const float totaltime{(m_tfix > -998.) ? m_tfix.value() : t_drift + timeOfFlight + t_surf}; // !< Total drift time
+            inserter(SiSurfaceCharge(position, SiCharge(q1, totaltime, hitproc, trklink)));
+          } else {
+            ATH_MSG_VERBOSE(std::fixed << std::setprecision(8) << "Local position (phi, eta, depth): ("
+                            << position.xPhi() << ", " << position.xEta() << ", " << position.xDepth() 
+                            << ") of the element is out of active area, charge = " << q1);
+          }
+        } // end of loop on charges
+      }
+    }
+  }
+  return;
+}
+
+// bool SCT_SurfaceChargesGenerator::chargeIsTrapped(double spess,
+//                                                   const SiDetectorElement* element,
+//                                                   double& trap_pos,
+//                                                   double& drift_time) const {
+//   if (element==nullptr) {
+//     ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::chargeIsTrapped element is nullptr");
+//     return false;
+//   }
+//   bool isTrapped{false};
+//   const IdentifierHash hashId{element->identifyHash()};
+//   const SCT_ChargeTrappingCondData condData{m_radDamageTool->getCondData(hashId, spess)};
+//   const double electric_field{condData.getElectricField()};
+
+//   if (m_doHistoTrap) {
+//     const double mobChar{condData.getHoleDriftMobility()};
+//     m_h_efieldz->Fill(spess, electric_field);
+//     m_h_efield->Fill(electric_field);
+//     m_h_mob_Char->Fill(electric_field, mobChar);
+//     m_h_vel->Fill(electric_field, electric_field * mobChar);
+//   }
+//   const double t_electrode{condData.getTimeToElectrode()};
+//   drift_time = condData.getTrappingTime();
+//   const double z_trap{condData.getTrappingPositionZ()};
+//   trap_pos = spess - z_trap;
+//   if (m_doHistoTrap) {
+//     m_h_drift_time->Fill(drift_time);
+//     m_h_t_electrode->Fill(t_electrode);
+//     m_h_drift_electrode->Fill(drift_time, t_electrode);
+//     m_h_ztrap_tot->Fill(z_trap);
+//   }
+//   // -- Calculate if the charge is trapped, and at which distance
+//   // -- Charge gets trapped before arriving to the electrode
+//   if (drift_time < t_electrode) {
+//     isTrapped = true;
+//     ATH_MSG_INFO("drift_time: " << drift_time << " t_electrode:  " << t_electrode << " spess " << spess);
+//     ATH_MSG_INFO("z_trap: " << z_trap);
+//     if (m_doHistoTrap) {
+//       m_h_ztrap->Fill(z_trap);
+//       m_h_trap_drift_t->Fill(drift_time);
+//       m_h_drift1->Fill(spess, drift_time / t_electrode);
+//       m_h_gen->Fill(spess, drift_time);
+//       m_h_gen1->Fill(spess, z_trap);
+//       m_h_gen2->Fill(spess, z_trap / drift_time * t_electrode);
+//       m_h_velocity_trap->Fill(electric_field, z_trap / drift_time);
+//       m_h_mobility_trap->Fill(electric_field, z_trap / drift_time / electric_field);
+//       m_h_trap_pos->Fill(trap_pos);
+//     }
+//   } else {
+//     isTrapped = false;
+//     if (m_doHistoTrap) {
+//       const double z_trap{condData.getTrappingPositionZ()};
+//       m_h_no_ztrap->Fill(z_trap);
+//       m_h_notrap_drift_t->Fill(drift_time);
+//     }
+//   }
+//   return isTrapped;
+// }
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.h b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.h
new file mode 100644
index 00000000..f9ae5fcd
--- /dev/null
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/SCT_SurfaceChargesGenerator.h
@@ -0,0 +1,164 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * Header file for SCT_SurfaceChargesGenerator Class
+ * @brief Class to drift the charged hits to the sensor surface for SCT
+ * version 1.0a Szymon Gadomski 31.05.2001
+ * @author Szymon.Gadomski@cern.ch, Awatif.Belymam@cern.ch, Davide.Costanzo@cern.ch,    
+ * tgcornel@nikhef.nl, Grant.Gorfine@cern.ch, Paul.Bell@cern.ch, Jorgen.Dalmau@cern.ch, 
+ * This is based on the SCTtest3SurfaceChargesGenerator
+ * compared to "test3", changes are all related to interfaces
+ * this should work with the new SCT_BarrelModuleSideDesign
+ * Compared to "test2" the following have been added in "test3":
+ * - a possibility to work with long steps and to smear charge along
+ *   the step in smaller steps
+ * - Lorentz angle
+ * 19/04/2001 -  change of hit class to SiTrackerHit
+ * version 1.0 Szymon Gadomski 09/06/2001, compiles with framework
+ * 26/07/2001 - changed to work with SiDigitization-00-02-00, tested
+ * 20/10/2002 - Awatif Belymam
+ * 29/10/2002 - the thickness of sensors is obtained from the objects
+ *            - of SCT_ModuleSideDesign type instead from its jobOptions file.
+ *            - Changes are done as well in jobOptions files.
+ * 06/01/2004 - Everything is now in CLHEP units (mm, ns, MeV)
+ * 23/08/2007 - Kondo.Gnanvo@cern.ch           
+ *            - Conversion of the SCT_SurfaceChargesGenerator code Al gTool
+ */
+
+#ifndef FASERSCT_DIGITIZATION_SCT_SURFACECHARGESGENERATOR_H
+#define FASERSCT_DIGITIZATION_SCT_SURFACECHARGESGENERATOR_H
+
+//Inheritance
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "FaserSCT_Digitization/ISCT_SurfaceChargesGenerator.h"
+
+#include "Identifier/IdentifierHash.h"
+// #include "InDetConditionsSummaryService/ISiliconConditionsTool.h"
+#include "InDetCondTools/ISiLorentzAngleTool.h"
+// #include "SCT_ConditionsTools/ISCT_RadDamageSummaryTool.h"
+// #include "SCT_ModuleDistortions/ISCT_ModuleDistortionsTool.h"
+#include "SiPropertiesTool/ISiPropertiesTool.h"
+
+// Gaudi
+#include "GaudiKernel/ITHistSvc.h" // for ITHistSvc
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ToolHandle.h"
+
+#include <iostream>
+
+// Charges and hits
+class FaserSiHit;
+
+// -- do charge trapping histos
+class ITHistSvc;
+class TH1F;
+class TH2F;
+class TProfile;
+
+namespace TrackerDD {
+  class SiDetectorElement;
+  class SCT_ModuleSideDesign;
+}
+
+namespace CLHEP {
+  class HepRandomEngine;
+}
+
+template <class HIT> class TimedHitPtr;
+
+class SCT_SurfaceChargesGenerator : public extends<AthAlgTool, ISCT_SurfaceChargesGenerator> {
+ public:
+
+  /**  constructor */
+  SCT_SurfaceChargesGenerator(const std::string& type, const std::string& name, const IInterface* parent);
+
+  /** Destructor */
+  virtual ~SCT_SurfaceChargesGenerator() = default;
+
+  /** AlgTool initialize */
+  virtual StatusCode initialize();
+
+  /** AlgTool finalize */
+  virtual StatusCode finalize();
+
+ private:
+
+  virtual void setFixedTime(float fixedTime)                             {m_tfix = fixedTime;}
+
+  /** create a list of surface charges from a hit */
+  virtual void process(const TrackerDD::SiDetectorElement* element, const TimedHitPtr<FaserSiHit>& phit, const ISiSurfaceChargesInserter& inserter, CLHEP::HepRandomEngine * rndmEngine) const;
+  void processSiHit(const TrackerDD::SiDetectorElement* element, const FaserSiHit& phit, const ISiSurfaceChargesInserter& inserter, float eventTime, unsigned short eventID, CLHEP::HepRandomEngine * rndmEngine) const;
+  
+  // some diagnostics methods are needed here too
+  float driftTime(float zhit, const TrackerDD::SiDetectorElement* element) const; //!< calculate drift time perpandicular to the surface for a charge at distance zhit from mid gap
+  float diffusionSigma(float zhit, const TrackerDD::SiDetectorElement* element) const; //!< calculate diffusion sigma from a gaussian dist scattered charge
+  float surfaceDriftTime(float ysurf) const; //!< Calculate of the surface drift time
+  float maxDriftTime(const TrackerDD::SiDetectorElement* element) const; //!< max drift charge equivalent to the detector thickness
+  float maxDiffusionSigma(const TrackerDD::SiDetectorElement* element) const; //!< max sigma diffusion
+
+  // trap_pos and drift_time are updated based on spess.
+//   bool chargeIsTrapped(double spess, const TrackerDD::SiDetectorElement* element, double& trap_pos, double& drift_time) const;
+
+  IntegerProperty m_numberOfCharges{this, "NumberOfCharges", 1, "number of charges"};
+  FloatProperty m_smallStepLength{this, "SmallStepLength", 5, "max internal step along the larger G4 step"};
+
+  /** related to the surface drift */
+  FloatProperty m_tSurfaceDrift{this, "SurfaceDriftTime", 10, "max surface drift time"};
+
+  FloatProperty m_tfix{this, "FixedTime", -999., "fixed time"};
+  FloatProperty m_tsubtract{this, "SubtractTime", -999., "subtract drift time from mid gap"};
+
+  BooleanProperty m_doDistortions{this, "doDistortions", false, "Simulation of module distortions"};
+  BooleanProperty m_useSiCondDB{this, "UseSiCondDB", false, "Usage of SiConditions DB values can be disabled to use setable ones"};
+  FloatProperty m_vdepl{this, "DepletionVoltage", 70., "depletion voltage, default 70V"};
+  FloatProperty m_vbias{this, "BiasVoltage", 150., "bias voltage, default 150V"};
+  BooleanProperty m_doTrapping{this, "doTrapping", false, "Flag to set Charge Trapping"};
+//   BooleanProperty m_doHistoTrap{this, "doHistoTrap", false, "Histogram the charge trapping effect"};
+  BooleanProperty m_doRamo{this, "doRamo", false, "Ramo Potential for charge trapping effect"};
+  BooleanProperty m_isOverlay{this, "isOverlay", false, "flag for overlay"};
+
+  //ToolHandles
+//   ToolHandle<ISCT_ModuleDistortionsTool> m_distortionsTool{this, "SCTDistortionsTool", "SCT_DistortionsTool", "Tool to retrieve SCT distortions"};
+  ToolHandle<ISiPropertiesTool> m_siPropertiesTool{this, "SiPropertiesTool", "SCT_SiPropertiesTool", "Tool to retrieve SCT silicon properties"};
+//   ToolHandle<ISCT_RadDamageSummaryTool> m_radDamageTool{this, "RadDamageSummaryTool", "SCT_RadDamageSummaryTool", "Tool to retrieve SCT radiation damages"};
+//   ToolHandle<ISiliconConditionsTool> m_siConditionsTool{this, "SiConditionsTool", "SCT_SiliconConditionsTool", "Tool to retrieve SCT silicon information"};
+  ToolHandle<ISiLorentzAngleTool> m_lorentzAngleTool{this, "LorentzAngleTool", "SiLorentzAngleTool/SCTLorentzAngleTool", "Tool to retreive Lorentz angle"};
+
+  ServiceHandle<ITHistSvc> m_thistSvc{this, "THistSvc", "THistSvc"};
+
+  float m_tHalfwayDrift{0.}; //!< Surface drift time
+  float m_distInterStrip{1.0}; //!< Inter strip distance normalized to 1
+  float m_distHalfInterStrip{0.}; //!< Half way distance inter strip
+
+  bool m_SurfaceDriftFlag{false}; //!< surface drift ON/OFF
+
+  // -- Histograms
+  TProfile* m_h_efieldz{nullptr};
+  TH1F* m_h_efield{nullptr};
+  TH1F* m_h_spess{nullptr};
+  TH1F* m_h_depD{nullptr};
+  TH2F* m_h_drift_electrode{nullptr};
+  TH1F* m_h_ztrap{nullptr};
+  TH1F* m_h_drift_time{nullptr};
+  TH1F* m_h_t_electrode{nullptr};
+  TH1F* m_h_zhit{nullptr};
+  TH1F* m_h_ztrap_tot{nullptr};
+  TH1F* m_h_no_ztrap{nullptr};
+  TH1F* m_h_trap_drift_t{nullptr};
+  TH1F* m_h_notrap_drift_t{nullptr};
+  TProfile* m_h_mob_Char{nullptr};
+  TProfile* m_h_vel{nullptr};
+  TProfile* m_h_drift1{nullptr};
+  TProfile* m_h_gen{nullptr};
+  TProfile* m_h_gen1{nullptr};
+  TProfile* m_h_gen2{nullptr};
+  TProfile* m_h_velocity_trap{nullptr};
+  TProfile* m_h_mobility_trap{nullptr};
+  TH1F* m_h_trap_pos{nullptr};
+};
+
+#endif // SCT_SURFACECHARGESGENERATOR_H
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/components/FaserSCT_Digitization_entries.cxx b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/components/FaserSCT_Digitization_entries.cxx
index dc705d93..ea833080 100644
--- a/Tracker/TrackerDigitization/FaserSCT_Digitization/src/components/FaserSCT_Digitization_entries.cxx
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/src/components/FaserSCT_Digitization_entries.cxx
@@ -1,16 +1,18 @@
-// #include "../SCT_Amp.h"
-// #include "../SCT_FrontEnd.h"
-// #include "../SCT_Digitization.h"
+#include "../SCT_Amp.h"
+#include "../SCT_FrontEnd.h"
+#include "../SCT_Digitization.h"
 #include "../SCT_DigitizationTool.h"
-// #include "../SCT_SurfaceChargesGenerator.h"
-// #include "../SCT_DetailedSurfaceChargesGenerator.h"
-// #include "../SCT_RandomDisabledCellGenerator.h"
+#include "../SCT_SurfaceChargesGenerator.h"
+#include "../SCT_RandomDisabledCellGenerator.h"
+// Unused by ATLAS
+// #include "../SCT_DetailedSurfaceChargesGenerator.h" 
 
-// DECLARE_COMPONENT( SCT_Digitization )
-// DECLARE_COMPONENT( SCT_Amp )  
-// DECLARE_COMPONENT( SCT_FrontEnd )
+DECLARE_COMPONENT( SCT_Amp )  
+DECLARE_COMPONENT( SCT_FrontEnd )
+DECLARE_COMPONENT( SCT_Digitization )
 DECLARE_COMPONENT( SCT_DigitizationTool )
-// DECLARE_COMPONENT( SCT_SurfaceChargesGenerator )
+DECLARE_COMPONENT( SCT_SurfaceChargesGenerator )
+DECLARE_COMPONENT( SCT_RandomDisabledCellGenerator )
+// Unused by ATLAS
 // DECLARE_COMPONENT( SCT_DetailedSurfaceChargesGenerator )
-// DECLARE_COMPONENT( SCT_RandomDisabledCellGenerator )
 
diff --git a/Tracker/TrackerSimEvent/TrackerSimEvent/FaserSiHit.h b/Tracker/TrackerSimEvent/TrackerSimEvent/FaserSiHit.h
index 8669b880..b17acf1d 100644
--- a/Tracker/TrackerSimEvent/TrackerSimEvent/FaserSiHit.h
+++ b/Tracker/TrackerSimEvent/TrackerSimEvent/FaserSiHit.h
@@ -141,8 +141,8 @@ private:
   HepMcParticleLink m_partLink;
   unsigned int m_ID;
 public:
-  // enum
-  //   { xDep = 2, xPhi = 0, xEta = 1};
+  enum
+    { xDep = 2, xPhi = 0, xEta = 1};
 };
 
 
-- 
GitLab