diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PDFcreator.h b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PDFcreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..9cd5083a324b11a7d0fa1a0d251ce037db00fd84
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PDFcreator.h
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// PDFcreator.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+	
+#ifndef ISF_PUNCHTHROUGHTOOLS_SRC_PDFCREATOR_H
+#define ISF_PUNCHTHROUGHTOOLS_SRC_PDFCREATOR_H
+	
+// Athena Base
+#include "AthenaKernel/IAtRndmGenSvc.h"
+	
+// ROOT includes
+#include "TFile.h"
+#include "TF1.h"
+#include "TH2F.h"
+	
+namespace ISF
+{
+	/** @class PDFcreator
+	     
+	 Creates random numbers with a distribution given as ROOT TF1.
+	 The TF1 function parameters will be retrieved from a histogram given by addPar.
+	
+	 @author  Elmar Ritsch <Elmar.Ritsch@cern.ch>
+	*/
+
+	class PDFcreator
+	{
+	
+	  public:
+	  /** construct the class with a given TF1 and a random engine */
+	  PDFcreator(TF1 *pdf, CLHEP::HepRandomEngine *engine):m_randomEngine(engine), m_pdf(pdf), m_randmin(0), m_randmax(0) {} ;
+
+	  ~PDFcreator() { };
+	
+	  /** all following is used to set up the class */
+	  void addPar(TH1 *hist) { m_par.push_back(hist); };             //!< get the function's parameter from the given histogram
+	  void setRange( TH1 *min, TH1 *max) { m_randmin = min; m_randmax = max; }; //!< get the function's range from the given histograms
+	
+	  /** get the random value with this methode, by providing the input parameters */
+	  double getRand( std::vector<double> inputPar, bool discrete = false, double randMin = 0., double randMax = 0.);
+	
+	  private:
+	  CLHEP::HepRandomEngine             *m_randomEngine;       //!< Random Engine 
+	  TF1                                *m_pdf;                //!< the probability density function
+	  TH1                                *m_randmin;            //!< the fit-functions minimum values
+	  TH1                                *m_randmax;            //!< the fit-functions maximum values
+	  std::vector<TH1*>                   m_par;                /*!< the 'histograms' which hold the parameters
+	                                                                     for the above PDF */
+	  };
+}
+	
+#endif
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PunchThroughParticle.h b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PunchThroughParticle.h
new file mode 100644
index 0000000000000000000000000000000000000000..f213e4e925715272301ebffd1350643779a786e3
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PunchThroughParticle.h
@@ -0,0 +1,112 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// PunchThroughParticle.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+	
+#ifndef ISF_PUNCHTHROUGHTOOLS_PUNCHTHROUGHPARTICLE_H
+#define ISF_PUNCHTHROUGHTOOLS_PUNCHTHROUGHPARTICLE_H
+	
+// ISF
+#include "PDFcreator.h"
+	
+// forward declarations
+class TH2F;
+	
+/*-------------------------------------------------------------------------
+ *  class PunchThroughParticle
+ *-------------------------------------------------------------------------*/
+namespace ISF
+{
+  /** @class PunchThroughParticle
+	     
+      This class holds information for different properties of a punch-through
+      particle (energy, theta, phi) distributions
+	
+      @author  Elmar Ritsch <Elmar.Ritsch@cern.ch>
+  */ 
+	 
+  class PunchThroughParticle
+  {
+    public:
+      PunchThroughParticle(int pdg, bool doAnti = false);           //!< set this particle's pdg code and if anti-particle should be done or not
+      ~PunchThroughParticle();
+	
+      /** set methods */
+      void setMinEnergy(double minEnergy);                          //!< the minimum energy with which these particles should be created
+      void setMaxNumParticles(int maxNum);                          //!< the maximum number of particles which will be created
+      void setNumParticlesFactor(double numFactor);                 //!< to scale the number of punch-through particles
+      void setEnergyFactor(double energyFactor);                    //!< to scale the energy of created particles
+      void setPosAngleFactor(double momAngleFactor);                //!< to scale the position deflection angles
+      void setMomAngleFactor(double momAngleFactor);                //!< to scale the momentum deviation of created particles
+      void setNumParticlesPDF(PDFcreator *pdf);                     //!< set the PDFcreator for the number of exit particles distribution
+      void setCorrelation(int corrPdg, TH2F *histLowE, TH2F *histHighE,
+                          double minCorrE = 0., double fullCorrE = 0., double lowE = 0.,
+                          double midE = 0., double upperE = 0.);     /*!< set the correlated particle type + correlation histograms
+                                                                         + full energy correlation threshold
+                                                                         + histogram domains histLowE:[lowE,midE] histHighE:[midE,upperE]*/
+      void setExitEnergyPDF(PDFcreator *pdf);                       //!< set the PDFcreator for the energy distribution
+      void setExitDeltaThetaPDF(PDFcreator *pdf);                   //!< set the PDFcreator for the deltaTheta distribution
+      void setExitDeltaPhiPDF(PDFcreator *pdf);                     //!< set the PDFcreator for the deltaPhi distribution
+      void setMomDeltaThetaPDF(PDFcreator *pdf);                    //!< set the PDFcreator for the momentumDeltaTheta distribution
+      void setMomDeltaPhiPDF(PDFcreator *pdf);                      //!< set the PDFcreator for the momentumDeltaPhi distribution
+
+	
+      /** get-access methods */
+      inline int getId()                        { return m_pdgId; };              //!< get this particle's pdg code
+      inline bool getdoAnti()                   { return m_doAnti; };             //!< get if anti-particles should be done or not
+      inline double getMinEnergy()              { return m_minEnergy; };          //!< the minimum energy with which these particles should be created
+      inline double getNumParticlesFactor()     { return m_numParticlesFactor; }; //!< to scale the number of punch-through particles
+      inline double getEnergyFactor()           { return m_energyFactor; };       //!< to scale the energy of created particles
+      inline double getPosAngleFactor()         { return m_posAngleFactor; };     //!< to scale the position deviation angles
+      inline double getMomAngleFactor()         { return m_momAngleFactor; };     //!< to scale the momentum deviation of created particles
+
+      inline int getMaxNumParticles()           { return m_maxNum; };             //!< the maximum number of particles which will be created
+      inline int getCorrelatedPdg()             { return m_corrPdg; };            //!< the correlated particle id
+      inline int getMinCorrelationEnergy()      { return m_corrMinEnergy; };      //!< minimum energy for correlation
+      inline int getFullCorrelationEnergy()     { return m_corrFullEnergy; };     //!< the full correlation energy
+      inline TH2F *getCorrelationLowEHist()     { return m_histCorrLowE; };       //!< the correlation histogram (low energies)
+      inline TH2F *getCorrelationHighEHist()    { return m_histCorrHighE; };      //!< the correlation histogram (high energies)
+      inline double *getCorrelationHistDomains(){ return m_corrHistDomains; };    //!< correlation histogram domains [lowE,midE,upperE]
+      inline PDFcreator *getNumParticlesPDF()   { return m_pdfNumParticles; };    //!< distribution parameters for the number of particles
+      inline PDFcreator *getExitEnergyPDF()     { return m_pdfExitEnergy; };      //!< distribution parameters for the exit energy
+      inline PDFcreator *getExitDeltaThetaPDF() { return m_pdfExitDeltaTheta; };  //!< distribution parameters for the exit delta theta
+      inline PDFcreator *getExitDeltaPhiPDF()   { return m_pdfExitDeltaPhi; };    //!< distribution parameters for the exit delta phi
+      inline PDFcreator *getMomDeltaThetaPDF()  { return m_pdfMomDeltaTheta;  };  //!< distribution parameters for the momentum delta theta
+      inline PDFcreator *getMomDeltaPhiPDF()    { return m_pdfMomDeltaPhi; };     //!< distribution parameters for the momentum delta phi
+	
+    private:
+      int                          m_pdgId;                     //!< the pdg-id of this particle
+      bool                         m_doAnti;                    //!< do also anti-particles?
+
+      /** some cut-parameters which will be set via python */
+      double                       m_minEnergy;                 //!< the minimum energy with which these particles should be created
+      int                          m_maxNum;                    //!< the maximum number of particles which will be created
+
+      /** some tuning-parameters which will be set via python */
+      double                       m_numParticlesFactor;        //!< scale the number of particles created
+      double                       m_energyFactor;              //!< scale the energy of this particle type
+      double                       m_posAngleFactor;            //!< scale the position deflection angles
+      double                       m_momAngleFactor;            //!< scale the momentum deviation 
+
+      /** all following stores the right distributions for all properties of the punch-through particles */
+      int                          m_corrPdg;                   //!< correlation to any other punch-through particle type
+      double                       m_corrMinEnergy;             //!< below this energy threshold, no particle correlation is computed
+      double                       m_corrFullEnergy;            /*!< holds the energy threshold above which
+                                                                     a particle correlation is fully developed */
+
+      TH2F*                        m_histCorrLowE;              //!< low energy correlation histogram (x:this particle, y:the correlated particle)
+      TH2F*                        m_histCorrHighE;             //!< high energy correlation histogram (x:this particle, y:the correlated particle)
+      double                      *m_corrHistDomains;           //!< correlation histogram domains
+      PDFcreator*                  m_pdfNumParticles;           //!< number of punch-through particles
+      PDFcreator*                  m_pdfExitEnergy;             //!< energy of punch-through particles
+      PDFcreator*                  m_pdfExitDeltaTheta;         //!< theta deviation of punch-through particles
+      PDFcreator*                  m_pdfExitDeltaPhi;           //!< phi deviation of punch-through particles
+      PDFcreator*                  m_pdfMomDeltaTheta;          //!< delta theta angle of punch-through particle momentum
+      PDFcreator*                  m_pdfMomDeltaPhi;            //!< delta phi angle of punch-through particle momentum
+  };
+}
+
+#endif
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PunchThroughTool.h b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PunchThroughTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..62150add0eaacca5b650b96f33798945091fc532
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/ISF_PunchThroughTools/PunchThroughTool.h
@@ -0,0 +1,183 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ISF_PUNCHTHROUGHTOOLS_SRC_PUNCHTHROUGHTOOL_H
+#define ISF_PUNCHTHROUGHTOOLS_SRC_PUNCHTHROUGHTOOL_H 1
+
+#include "ISF_FastCaloSimInterfaces/IPunchThroughTool.h"
+#include <string>
+
+// Athena Base
+#include "AthenaBaseComps/AthAlgTool.h"
+
+#include "BarcodeInterfaces/Barcode.h"
+#include "BarcodeInterfaces/PhysicsProcessCode.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+
+/*-------------------------------------------------------------------------
+ *  Forward declarations
+ *-------------------------------------------------------------------------*/
+
+class IPartPropSvc;
+class IAtRndmGenSvc;
+class TFile;
+class IEnvelopeDefSvc;
+
+namespace CLHEP {
+  class HepRandomEngine;
+}
+	
+namespace HepPDT {
+  class ParticleDataTable;
+}
+	
+namespace HepMC {
+  class GenEvent;
+}
+
+namespace Barcode {
+  class IBarcodeSvc;
+}
+	
+namespace ISF {
+
+  class PunchThroughParticle;
+  class PDFcreator;
+  class IGeoIDSvc;
+}
+
+namespace ISF {
+	 
+  class PunchThroughTool : virtual public IPunchThroughTool,
+	                   public AthAlgTool
+  {
+    public:
+    /** Constructor */
+    PunchThroughTool(const std::string&,const std::string&,const IInterface*);
+	   
+    /** Destructor */
+    virtual ~PunchThroughTool ();
+	   
+    /** AlgTool initialize method */
+    virtual StatusCode initialize();
+    /** AlgTool finalize method */
+    virtual StatusCode finalize  ();
+    /** interface function: fill a vector with the punch-through particles */
+    const ISF::ISFParticleContainer* computePunchThroughParticles(const ISF::ISFParticle &isfp) const;
+	
+      private:
+   /*---------------------------------------------------------------------
+    *  Private member functions
+    *---------------------------------------------------------------------*/
+    /** registers a type of punch-through particles which will be simulated */
+        StatusCode registerParticle(int pdgID, bool doAntiparticle = false, 
+                                double minEnergy = 0., int maxNumParticles = -1,
+                                double numParticlesFactor = 1., double energyFactor = 1.,
+                                double posAngleFactor = 1.,
+                                double momAngleFactor = 1.);
+    /** register a correlation for the two given types of punch-through particles
+	with a given energy threshold above which we will have full correlation */
+	StatusCode registerCorrelation(int pdgID1, int pdgID2,double minCorrEnergy = 0., double fullCorrEnergy = 0.);
+	
+    /** reads out the lookuptable for the given type of particle */
+	PDFcreator *readLookuptablePDF(int pdgID, std::string folderName);
+	
+    /** create the right number of punch-through particles for the given pdg
+	     *  and return the number of particles which was created. also create these
+    *  particles with the right distributions (energy, theta, phi).
+	     *  if a second argument is given, create exactly this number of particles
+	     *  (also with the right energy,theta,phi distributions */
+	int getAllParticles(int pdg, int numParticles = -1) const;
+	
+    /** get the right number of particles for the given pdg while considering
+     *  the correlation to an other particle type, which has already created
+     *  'corrParticles' number of particles */
+	int getCorrelatedParticles(int doPdg, int corrParticles ) const;
+	
+    /** create exactly one punch-through particle with the given pdg and the given max energy */
+	ISF::ISFParticle *getOneParticle(int pdg, double maxEnergy) const;
+	
+    /** create a ISF Particle state at the MS entrace containing a particle with the given properties */
+	ISF::ISFParticle *createExitPs(int PDGcode, double energy, double theta, double phi, double momTheta, double momPhi) const;
+
+    /** get the floating point number in a string, after the given pattern */
+        double getFloatAfterPatternInStr(const char *str, const char *pattern);
+    /** get particle through the calorimeter */
+        Amg::Vector3D propagator(double theta, double phi) const;
+
+    /*---------------------------------------------------------------------
+     *  Private members
+     *---------------------------------------------------------------------*/
+	   	
+    /** initial particle properties */
+	mutable const ISF::ISFParticle*	     m_initPs;         //!< the incoming particle
+	mutable double                       m_initEnergy;     //!< the incoming particle's energy
+    	mutable double                       m_initEta;        //!< the incoming particle's eta
+	mutable double                       m_initTheta;      //!< the incoming particle's theta
+	mutable double                       m_initPhi;        //!< the incoming particle's phi
+
+    /** calo-MS borders */
+	double 				     R1, R2, z1, z2;
+
+    /** the returned vector of ISFParticles */
+	mutable ISF::ISFParticleContainer  *m_isfpCont;
+
+    /** parent event */
+	mutable HepMC::GenEvent*            m_parentGenEvt;    //!< all newly created particles/vertices will have this common parent
+
+    /** ParticleDataTable needed to get connection pdg_code <-> charge */
+	const HepPDT::ParticleDataTable*    m_particleDataTable;
+	
+    /** random generator service */
+	ServiceHandle<IAtRndmGenSvc>        m_randomSvc;                //!< Random Svc
+	std::string                         m_randomEngineName;         //!< Name of the random number stream
+	CLHEP::HepRandomEngine*             m_randomEngine;             //!< Random Engine 
+	
+    /** ROOT objects */
+	TFile*                              m_fileLookupTable;          //!< the punch-through lookup table file
+    /** general information of the punch-through particles which will be created */
+	mutable std::map<int, bool>         m_doAntiParticleMap;        /*!< stores information, if anti-particles are
+	                                                                         created for any given PDG id */
+    /** needed to create punch-through particles with the right distributions */
+	mutable std::map<int, PunchThroughParticle*> m_particles;       //!< store all punch-through information for each particle id
+	
+    /** barcode steering */
+
+	mutable Barcode::PhysicsProcessCode m_processCode;
+	mutable Barcode::ParticleBarcode    m_primBC;
+	mutable Barcode::ParticleBarcode    m_secBC;
+
+	/*---------------------------------------------------------------------
+	     *  Properties
+	 *---------------------------------------------------------------------*/
+	
+    /** Properties */
+	std::string                          m_filenameLookupTable;     //!< holds the filename of the lookup table (property)
+	std::vector<int>                     m_pdgInitiators;           //!< vector of punch-through initiator pgds
+	std::vector<int>                     m_punchThroughParticles;   //!< vector of pdgs of the particles produced in punch-throughs
+	std::vector<bool>                    m_doAntiParticles;         //!< vector of bools to determine if anti-particles are created for each punch-through particle type
+    	std::vector<int>                     m_correlatedParticle;      //!< holds the pdg of the correlated particle for each given pdg
+    	std::vector<double>                  m_minCorrEnergy;           //!< holds the energy threshold below which no particle correlation is computed
+    	std::vector<double>                  m_fullCorrEnergy;          //!< holds the energy threshold above which a particle correlation is fully developed
+    	std::vector<double>                  m_posAngleFactor;          //!< tuning parameter to scale the position deflection angles
+    	std::vector<double>                  m_momAngleFactor;          //!< tuning parameter to scale the momentum deflection angles
+    	std::vector<double>                  m_minEnergy;               //!< punch-through particles minimum energies
+    	std::vector<int>                     m_maxNumParticles;         //!< maximum number of punch-through particles for each particle type
+    	std::vector<double>                  m_numParticlesFactor;      //!< scale the number of punch-through particles
+    	std::vector<double>                  m_energyFactor;            //!< scale the energy of the punch-through particles
+	
+    /*---------------------------------------------------------------------
+     *  ServiceHandles
+     *---------------------------------------------------------------------*/
+	ServiceHandle<IPartPropSvc>          m_particlePropSvc;         //!< particle properties svc
+	ServiceHandle<IGeoIDSvc>	     m_geoIDSvc;
+	ServiceHandle<Barcode::IBarcodeSvc>  m_barcodeSvc;
+        ServiceHandle<IEnvelopeDefSvc>       m_envDefSvc;
+
+    /** beam pipe radius */
+	double				    m_beamPipe;
+  }; 
+}
+	
+#endif
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/cmt/requirements b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/cmt/requirements
new file mode 100644
index 0000000000000000000000000000000000000000..2ced03874e05630f45318bd246a8442988e3a7ed
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/cmt/requirements
@@ -0,0 +1,49 @@
+package ISF_PunchThroughTools
+	
+manager Andreas Salzburger <Andreas.Salzburger@cern.ch>
+manager Elmar Ritsch <Elmar.Ritsch@cern.ch>
+manager Wolfgang Lukas <Wolfgang.Lukas@cern.ch>
+	
+public
+use AtlasPolicy              AtlasPolicy-*
+use BarcodeInterfaces        BarcodeInterfaces-*     Simulation/Barcode
+	
+########## Control #############################################################
+
+use AthenaKernel             AthenaKernel-*             Control
+use AthenaBaseComps          AthenaBaseComps-*          Control
+use AtlasROOT                AtlasROOT-*                External
+
+use ISF_FastCaloSimInterfaces  ISF_FastCaloSimInterfaces-*   Simulation/ISF/ISF_FastCaloSim
+
+########## Tracking ############################################################
+
+use GeoPrimitives            GeoPrimitives-*            DetectorDescription
+
+private
+
+use DataModel		     DataModel-* 		Control
+use GaudiInterface           GaudiInterface-*           External
+use SubDetectorEnvelopes  SubDetectorEnvelopes-*  AtlasGeometryCommon	
+########## External ############################################################
+use AtlasCLHEP               AtlasCLHEP-*               External
+use AtlasHepMC               AtlasHepMC-*               External
+
+########## ISF #################################################################
+use ISF_Event                  ISF_Event-*                   Simulation/ISF/ISF_Core
+use ISF_Interfaces             ISF_Interfaces-*              Simulation/ISF/ISF_Core   
+
+##############################################
+use HepPDT                     v*                       LCG_Interfaces
+use PathResolver            PathResolver-*              Tools
+
+declare_runtime_extras extras = ../Data/*.root
+
+public
+library ISF_PunchThroughTools *.cxx components/*.cxx
+apply_pattern component_library
+	
+# use the following to compile with debug information
+#private
+#macro cppdebugflags '$(cppdebugflags_s)'
+#macro_remove componentshr_linkopts "-Wl,-s"
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PDFcreator.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PDFcreator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d16d6a0f335f2ed9253878a467c84a77d98908df
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PDFcreator.cxx
@@ -0,0 +1,164 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// PDFcreator.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+	
+// class header
+#include "ISF_PunchThroughTools/PDFcreator.h"
+	
+// Random number generators
+#include "CLHEP/Random/RandFlat.h"
+	
+// ROOT
+#include "TFile.h"
+#include "TH2F.h"
+#include "TAxis.h"
+#include "TRandom.h"
+	
+/*=========================================================================
+*  DESCRIPTION OF FUNCTION:
+*  ==> see headerfile
+*=======================================================================*/
+double ISF::PDFcreator::getRand(std::vector<double> inputParameters, bool discrete, double randMin, double randMax)
+{
+// Since the histograms which hold the function's fit parameters are binned
+// we have to choose which bin we use for the current energy & eta regime.
+// It's very unlikely to exactly hit a bin's center, therefore we randomly
+// choose either the lower next or the upper next bin.
+	
+  int numInputPar = inputParameters.size();
+  TAxis **axis = new TAxis*[numInputPar];
+  Int_t *chosenBin = new Int_t[numInputPar];
+	
+	
+// get the axis from the first (could be any other too, but the first one
+// always exists) histogram (which holds the function's first fit parameter)
+  axis[0] = m_par[0]->GetXaxis();
+  axis[1] = m_par[0]->GetYaxis();
+	
+// loop over all input inputParameters (e.g. eta & energy)
+  for (int inputPar=0; inputPar<numInputPar; inputPar++) {
+    // store the axis for the current inputParameter
+    TAxis *curaxis = axis[inputPar];
+    double curvalue = inputParameters[inputPar];
+	
+    // get the id of the bin corresponding to the current value
+    // (use FindFixBin to avoid the axis from being rebinned)
+    Int_t bin = curaxis->FindFixBin(curvalue);
+    // get the center of the closest bin to the input inputParameter
+    double closestCenter = curaxis->GetBinCenter(bin);
+    // get the bins edge closest to the current value
+    // and find out if the next closest bin has id bin+1 or bin-1
+    double closestEdge = (curvalue <= closestCenter) ? curaxis->GetBinLowEdge(bin) : curaxis->GetBinUpEdge(bin);
+    int binDelta = (curvalue <= closestCenter) ? -1 : +1;
+	
+    // Calculate the 'normalised distance' between the input-value,
+    // the closest bin's center and this bin's closest edge
+    // distance == 0 means that the input value lies exactly on its closest bin's center.
+    // distance == 0.5 means that the input value lies exactly on the edge to the next bin
+    double distance = (curvalue - closestCenter) / (closestEdge - closestCenter) / 2.;
+	
+    // now randomly choose if we take the closest bin or the one next to the closest one.
+    // with this, we kind of linearly interpolate between two bins if an input value
+    // betweeen these two bins does occure many times.
+    double rand = CLHEP::RandFlat::shoot(m_randomEngine);
+    chosenBin[inputPar] = ( rand >= distance ) ? bin : bin+binDelta;
+	
+    // check if we have chosen an over- or underflow-bin
+    // if this has happened, choose the last bin still in range
+
+    if ( chosenBin[inputPar] <= 0 )				chosenBin[inputPar] = 1;
+    else if ( chosenBin[inputPar] > curaxis->GetNbins() )   	chosenBin[inputPar] = curaxis->GetNbins();
+  }
+	
+  // now get the bin number (since all histograms are binned
+  // in exactly the same way it should be the same for all
+  // of them)
+  Int_t bin = 0;
+  if (numInputPar == 1)		    bin = m_par[0]->GetBin( chosenBin[0] );
+  else if (numInputPar ==2 )	    bin = m_par[0]->GetBin( chosenBin[0], chosenBin[1] );
+  else if (numInputPar == 3)	    bin = m_par[0]->GetBin( chosenBin[0], chosenBin[1], chosenBin[2] ); 
+  // TODO: implement case of >3 input parameters
+	
+  // free some memory
+  delete [] axis;
+
+  // fill in the parameters into the distribution-function
+  // (e.g. for the current energy & eta regime)
+  for (int funcPar = 0; funcPar < m_pdf->GetNpar(); funcPar++) {
+    double value = m_par[funcPar]->GetBinContent(bin);
+    m_pdf->SetParameter(funcPar, value);
+  }
+	
+  // now finally we can determine the random number from the given distribution
+  //
+  // set the minimum and maximum random values
+  double xMin = ( (randMin != 0.) && (randMin <  m_randmax->GetBinContent(bin)) )
+	                          ? randMin : m_randmin->GetBinContent(bin);
+  double xMax = ( (randMax != 0.) && (randMax <= m_randmax->GetBinContent(bin)) )
+                                  ? randMax : m_randmax->GetBinContent(bin);
+	
+  // free some more memory
+  delete [] chosenBin;
+	
+  // (1.) for discrete distributions
+  //       - this is implemented separately from the continuous case,
+  //         since it significantly speeds up the creation of random
+  //         numbers from a distribution with a high negative gradient
+  //       - for this the sum( f(x_i) ) has to be normalized !
+  if (discrete) {
+    // get a flat random value between 0. and 1.
+    double flat = CLHEP::RandFlat::shoot(m_randomEngine);
+
+    double sum = 0.;
+	
+    // set the minimum x value
+    xMin = lround(xMin);
+	
+    // now determine the corresponding value from the distribution
+    for (int rand=xMin; rand<lround(xMax); rand++) {
+      // sum up the probabilities for each current bin
+      sum += m_pdf->Eval(rand);
+      // if the sum gets larger than the random value
+      //   -> the current 'rand' is the value from the distribution
+      //   -> return this value
+      if (sum >= flat) return ((double)rand);
+    }
+	
+    // This point is reached if the the x value corresponding to the random
+    // value is the maximum possible value in the probability distribution
+    // or if the distribution is not normalized.
+    //    -> return the maximum value
+    return (double)m_pdf->GetXmax();
+  }
+	
+	
+  // (2.) for continuous distributions
+  //      * algorithmus: rejection sampling
+  else {
+    // find max and min values in the PDF
+    double yMin = m_pdf->GetMinimum(xMin, xMax);
+    //if (yMin < 0.) yMin = 0.; // in case the PDF contains negative values
+    double yMax = m_pdf->GetMaximum(xMin, xMax);
+	
+    // now get a random value rx with the right distribution
+    //  - use the count variable just for backup to prevent
+    //    an endless loop
+    for (int count=0; count < 1e7; count++) {
+      // first choose a random value within [yMin, yMax]
+      double ry = CLHEP::RandFlat::shoot(m_randomEngine)*(yMax-yMin) + yMin;
+      // then choose a random value within [xMin, xMax]
+      double rx = CLHEP::RandFlat::shoot(m_randomEngine)*(xMax-xMin) + xMin;
+      // calculate y=pdf(rx)
+      double y = m_pdf->Eval(rx);
+      // if ry<=pdf(rx) is fulfilled, we have our random value
+      if ( ry <= y ) return rx;
+      }
+  }
+	
+  // this point will only be reached, if something went wrong
+  return 0.;
+}
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PunchThroughParticle.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PunchThroughParticle.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e521f618a701c527e9df49ec6560ab72a8696a83
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PunchThroughParticle.cxx
@@ -0,0 +1,182 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// PunchThroughParticle.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+	
+// class header
+#include "ISF_PunchThroughTools/PunchThroughParticle.h"
+	
+// ROOT
+#include "TH2F.h"
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+ISF::PunchThroughParticle::PunchThroughParticle(int pdg, bool doAnti):
+        m_pdgId(pdg),
+        m_doAnti(doAnti),
+        m_minEnergy(0.),
+        m_maxNum(-1),
+        m_numParticlesFactor(1.),
+        m_energyFactor(1.),
+        m_posAngleFactor(1.),
+        m_momAngleFactor(1.),
+        m_corrPdg(0),
+        m_corrMinEnergy(0),
+        m_corrFullEnergy(0),
+        m_histCorrLowE(0),
+        m_histCorrHighE(0),
+        m_corrHistDomains(0),
+        m_pdfNumParticles(0),	//does this number ever change?
+        m_pdfExitEnergy(0),
+        m_pdfExitDeltaTheta(0),
+        m_pdfExitDeltaPhi(0),
+        m_pdfMomDeltaTheta(0),
+        m_pdfMomDeltaPhi(0)
+{ }
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setMinEnergy(double minEnergy)
+{ 
+  m_minEnergy = minEnergy;
+}
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setMaxNumParticles(int maxNum)
+{
+  m_maxNum = maxNum;
+}
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setNumParticlesFactor(double numFactor)
+{
+  m_numParticlesFactor = numFactor;
+}
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setEnergyFactor(double energyFactor)
+{
+  m_energyFactor = energyFactor;
+}
+	
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+void ISF::PunchThroughParticle::setPosAngleFactor(double posAngleFactor)
+{
+  m_posAngleFactor = posAngleFactor;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+void ISF::PunchThroughParticle::setMomAngleFactor(double momAngleFactor)
+{
+  m_momAngleFactor = momAngleFactor;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setNumParticlesPDF(PDFcreator *pdf)
+{
+  m_pdfNumParticles = pdf;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setCorrelation(int corrPdg,
+    TH2F *histLowE, TH2F *histHighE,
+    double minCorrelationEnergy,
+    double fullCorrelationEnergy,
+    double lowE,
+    double midE, 
+    double upperE)
+{
+  m_corrPdg = corrPdg;
+  m_histCorrLowE = histLowE;
+  m_histCorrHighE = histHighE;
+  m_corrMinEnergy = minCorrelationEnergy;
+  m_corrFullEnergy = fullCorrelationEnergy;
+
+  m_corrHistDomains = new double [3];
+  m_corrHistDomains[0] = lowE;
+  m_corrHistDomains[1] = midE;
+  m_corrHistDomains[2] = upperE;
+}
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setExitEnergyPDF(PDFcreator *pdf)
+{
+  m_pdfExitEnergy = pdf;
+}
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setExitDeltaThetaPDF(PDFcreator *pdf)
+{
+  m_pdfExitDeltaTheta = pdf;
+}
+	
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+void ISF::PunchThroughParticle::setExitDeltaPhiPDF(PDFcreator *pdf)
+{
+  m_pdfExitDeltaPhi = pdf;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+void ISF::PunchThroughParticle::setMomDeltaThetaPDF(PDFcreator *pdf)
+{
+  m_pdfMomDeltaTheta = pdf;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+void ISF::PunchThroughParticle::setMomDeltaPhiPDF(PDFcreator *pdf)
+{
+  m_pdfMomDeltaPhi = pdf;
+}
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PunchThroughTool.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PunchThroughTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ca6eadb52854c0aa0585b51bc80db46c85700021
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/PunchThroughTool.cxx
@@ -0,0 +1,1060 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// PunchThroughTool.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+// class header
+#include "ISF_PunchThroughTools/PunchThroughTool.h"		
+
+// standard C++ libraries
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <algorithm>
+#include <vector>
+
+// standard C libraries
+#include <math.h>
+
+// Control
+#include "DataModel/DataVector.h"
+
+// Gaudi & StoreGate
+#include "GaudiKernel/IPartPropSvc.h"
+
+// HepMC
+#include "HepMC/SimpleVector.h"
+#include "HepMC/GenVertex.h"
+#include "HepMC/GenParticle.h"
+#include "HepMC/GenEvent.h"
+#include "HepPDT/ParticleDataTable.hh"
+
+// CLHEP
+#include "CLHEP/Random/RandFlat.h"
+
+// ROOT
+#include "TFile.h"
+#include "TH2F.h"
+#include "TAxis.h"
+#include "TH1.h"
+#include "TRandom.h"
+#include "TMath.h"
+
+// PathResolver
+#include "PathResolver/PathResolver.h"
+
+//ISF
+#include "ISF_Event/ISFParticle.h"
+#include "ISF_PunchThroughTools/PDFcreator.h"
+#include "ISF_PunchThroughTools/PunchThroughParticle.h"
+#include "ISF_Interfaces/IGeoIDSvc.h"
+
+//Barcode
+#include "BarcodeInterfaces/IBarcodeSvc.h"
+
+//Geometry
+#include "SubDetectorEnvelopes/IEnvelopeDefSvc.h"
+
+//Amg
+#include "GeoPrimitives/GeoPrimitivesHelpers.h"
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+ISF::PunchThroughTool::PunchThroughTool( const std::string& type,
+                                            const std::string& name,
+                                            const IInterface*  parent )
+ : AthAlgTool(type, name, parent),
+   m_parentGenEvt(0),
+   m_particleDataTable(0),
+   m_randomSvc("AtDSFMTGenSvc", name),
+   m_randomEngineName("ISFRnd"),
+   m_randomEngine(0),
+   m_filenameLookupTable("CaloPunchThroughParametrisation.root"),
+   m_pdgInitiators(),
+   m_punchThroughParticles(),
+   m_doAntiParticles(),
+   m_correlatedParticle(),
+   m_minCorrEnergy(),
+   m_fullCorrEnergy(),
+   m_posAngleFactor(),
+   m_momAngleFactor(),
+   m_minEnergy(),
+   m_maxNumParticles(),
+   m_numParticlesFactor(),
+   m_energyFactor(),
+   m_particlePropSvc("PartPropSvc",name),
+   m_geoIDSvc("iGeant4::G4PolyconeGeoIDSvc/ISF_G4PolyconeGeoIDSvc",name),
+   m_barcodeSvc("BarcodeSvc",name),
+   m_envDefSvc("AtlasGeometry_EnvelopeDefSvc",name),
+   m_beamPipe(500.)
+{
+  // declare this as an interface
+  declareInterface<IPunchThroughTool>(this);
+  
+  // property definition and initialization - allows to set variables from python
+
+  declareProperty( "FilenameLookupTable",          m_filenameLookupTable   );
+  declareProperty( "PunchThroughInitiators",       m_pdgInitiators         );
+  declareProperty( "PunchThroughParticles",        m_punchThroughParticles );
+  declareProperty( "DoAntiParticles",              m_doAntiParticles       );
+  declareProperty( "CorrelatedParticle",           m_correlatedParticle    );
+  declareProperty( "MinCorrelationEnergy",         m_minCorrEnergy         );
+  declareProperty( "FullCorrelationEnergy",        m_fullCorrEnergy        );
+  declareProperty( "ScalePosDeflectionAngles",     m_posAngleFactor        );
+  declareProperty( "ScaleMomDeflectionAngles",     m_momAngleFactor        );
+  declareProperty( "MinEnergy",                    m_minEnergy             );
+  declareProperty( "MaxNumParticles",              m_maxNumParticles       );
+  declareProperty( "NumParticlesFactor",           m_numParticlesFactor    );
+  declareProperty( "EnergyFactor",                 m_energyFactor          );
+  declareProperty( "RandomNumberService",          m_randomSvc,        	   "Random number generator"         );
+  declareProperty( "RandomStreamName",             m_randomEngineName,     "Name of the random number stream");
+  declareProperty( "BarcodeSvc",                   m_barcodeSvc            );
+  declareProperty( "EnvelopeDefSvc",               m_envDefSvc             );
+  declareProperty( "BeamPipeRadius",		   m_beamPipe		   );
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+ISF::PunchThroughTool::~PunchThroughTool()
+{}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+StatusCode ISF::PunchThroughTool::initialize() 
+{
+  ATH_MSG_INFO( "initialize()" );
+
+  // resolving lookuptable file
+  std::string resolvedFileName = PathResolver::find_file (m_filenameLookupTable, "DATAPATH");
+  if (resolvedFileName != "")
+  {
+    ATH_MSG_INFO( "[ punchthrough ] Parameterisation file found: " << resolvedFileName );
+  }
+  else 
+  {
+    ATH_MSG_ERROR( "[ punchthrough ] Parameterisation file not found" );
+    return StatusCode::FAILURE;
+  }
+
+  // open the LookupTable file
+  m_fileLookupTable = new TFile( resolvedFileName.c_str(), "READ");
+  if (!m_fileLookupTable) 
+  {
+    ATH_MSG_WARNING("[ punchthrough ] unable to open the lookup-tabel for the punch-through simulation (file does not exist)");
+    return StatusCode::FAILURE;
+  }
+
+  if (!m_fileLookupTable->IsOpen()) 
+  {
+    ATH_MSG_WARNING("[ punchthrough ] unable to open the lookup-tabel for the punch-through simulation (wrong or empty file?)");
+    return StatusCode::FAILURE;
+  }
+
+  // retrieve the ParticleProperties handle
+  if ( m_particlePropSvc.retrieve().isFailure() ) 
+  {
+     ATH_MSG_FATAL( "[ punchthrough ] Can not retrieve " << m_particlePropSvc << " ! Abort. " );
+     return StatusCode::FAILURE;
+  }
+
+  // and the particle data table 
+  m_particleDataTable = m_particlePropSvc->PDT();
+  if (m_particleDataTable==0) 
+  {
+    ATH_MSG_FATAL( " [ punchthrough ] Could not get ParticleDataTable! Cannot associate pdg code with charge! Abort. " );
+    return StatusCode::FAILURE;
+  }
+
+  // Random number service
+  if ( m_randomSvc.retrieve().isFailure() ) 
+  {
+    ATH_MSG_ERROR( "[ punchthrough ] Could not retrieve " << m_randomSvc );
+    return StatusCode::FAILURE;
+  }
+
+  // Get own engine with own seeds:
+  m_randomEngine = m_randomSvc->GetEngine(m_randomEngineName);
+  if (!m_randomEngine) 
+  {
+    ATH_MSG_ERROR( "[ punchthrough ] Could not get random engine '" << m_randomEngineName << "'" );
+    return StatusCode::FAILURE;
+  }
+
+  // Geometry identifier service
+  if ( !m_geoIDSvc.empty() && m_geoIDSvc.retrieve().isFailure()) 
+  {
+    ATH_MSG_FATAL ( "[ punchthrough ] Could not retrieve GeometryIdentifier Service. Abort");
+    return StatusCode::FAILURE;
+  }
+
+  //barcode service
+
+  if (m_barcodeSvc.retrieve().isFailure() )
+  {
+    ATH_MSG_ERROR( "[ punchthrough ] Could not retrieve " << m_barcodeSvc );
+    return StatusCode::FAILURE;
+  }
+  
+  //envelope definition service
+  if (m_envDefSvc.retrieve().isFailure() )
+  {
+    ATH_MSG_ERROR( "[ punchthrough ] Could not retrieve " << m_envDefSvc );
+    return StatusCode::FAILURE;
+  }
+
+//--------------------------------------------------------------------------------
+  // register all the punch-through particles which will be simulated
+  for ( unsigned int num = 0; num < m_punchThroughParticles.size(); num++ ) 
+  {
+    int pdg = m_punchThroughParticles[num];
+    // if no information is given on the creation of anti-particles -> do not simulate anti-particles
+    bool doAnti = ( num < m_doAntiParticles.size() ) ? m_doAntiParticles[num] : false;
+    // if no information is given on the minimum energy -> take 50. MeV as default
+    double minEnergy = ( num < m_minEnergy.size() ) ? m_minEnergy[num] : 50.;
+    // if no information is given on the maximum number of punch-through particles -> take -1 as default
+    int maxNum = ( num < m_minEnergy.size() ) ? m_maxNumParticles[num] : -1;
+    // if no information is given on the scale factor for the number of particles -> take 1. as defaulft
+    double numFactor = ( num < m_numParticlesFactor.size() ) ? m_numParticlesFactor[num] : 1.;
+    // if no information is given on the position angle factor -> take 1.
+    double posAngleFactor = ( num < m_posAngleFactor.size() ) ? m_posAngleFactor[num] : 1.;
+    // if no information is given on the momentum angle factor -> take 1.
+    double momAngleFactor = ( num < m_momAngleFactor.size() ) ? m_momAngleFactor[num] : 1.;
+    // if no information is given on the scale factor for the energy -> take 1. as default
+    double energyFactor = ( num < m_energyFactor.size() ) ? m_energyFactor[num] : 1.;
+
+    // register the particle
+    ATH_MSG_VERBOSE("[ punchthrough ] registering punch-through particle type with pdg = " << pdg );
+    if ( registerParticle( pdg, doAnti, minEnergy, maxNum, numFactor, energyFactor, posAngleFactor, momAngleFactor )
+         != StatusCode::SUCCESS) 
+    {
+      ATH_MSG_ERROR("[ punchthrough ] unable to register punch-through particle type with pdg = " << pdg);
+    }
+  }
+
+  // TODO: implement punch-through parameters for different m_pdgInitiators
+  //       currently m_pdgInitiators is only used to filter out particles
+
+  // check if more correlations were given than particle types were registered
+  unsigned int numCorrelations = m_correlatedParticle.size();
+  if ( numCorrelations > m_punchThroughParticles.size() ) 
+  {
+      ATH_MSG_WARNING("[ punchthrough ] more punch-through particle correlations are given, than punch-through particle types are registered (skipping the last ones)");
+      numCorrelations = m_punchThroughParticles.size();
+  }
+
+  // now register correlation between particles
+  for ( unsigned int num = 0; num < numCorrelations; num++ ) 
+  {
+    int pdg1 = m_punchThroughParticles[num];
+    int pdg2 = m_correlatedParticle[num];
+    double fullCorrEnergy = ( num < m_fullCorrEnergy.size() ) ? m_fullCorrEnergy[num] : 0.;
+    double minCorrEnergy = ( num < m_minCorrEnergy.size() ) ?  m_minCorrEnergy[num] : 0.;
+
+    // if correlatedParticle==0 is given -> no correlation
+    if ( ! pdg2) continue;
+    // register it
+    if ( registerCorrelation(pdg1, pdg2, minCorrEnergy, fullCorrEnergy) != StatusCode::SUCCESS ) 
+    {
+      ATH_MSG_ERROR("[ punchthrough ] unable to register punch-through particle correlation for pdg1=" << pdg1 << " pdg2=" << pdg2 );
+    }
+  }
+
+  // get the calo-MS border coordinates. Look at calo and MS geometry definitions, if same R and Z -> boundary surface
+
+  RZPairVector* rzMS = &(m_envDefSvc->getMuonRZValues());
+  RZPairVector* rzCalo = &(m_envDefSvc->getCaloRZValues());
+
+  bool found1, found2; 
+  found1=false; found2=false;
+
+  for ( size_t i=0; i<rzCalo->size();++i)
+  {
+    double r_tempCalo = rzCalo->at(i).first;
+    double z_tempCalo = rzCalo->at(i).second;
+
+    if (r_tempCalo> m_beamPipe)
+    { 
+      for ( size_t j=0; j<rzMS->size();++j)
+      {
+      double r_tempMS =rzMS->at(j).first;
+      double z_tempMS =rzMS->at(j).second;
+
+      if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && found1==false ) 
+      { 
+        R1=r_tempMS;
+        z1=fabs(z_tempMS);
+        found1=true;
+        continue;
+      }
+      else if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && r_tempCalo!=R1 && fabs(z_tempCalo)!=z1)
+      { 
+        R2=r_tempMS; 
+        z2=fabs(z_tempMS); 
+        found2=true;
+      }
+    }
+
+    if (found1==true && found2==true) break;
+    }
+  }
+
+  //in case geometry description changes
+  if (found1 == false) ATH_MSG_ERROR ("first coordinate of calo-MS border not found");
+  if (found2 == false) ATH_MSG_ERROR ("second coordinate of calo-MS border not found; first one is: R1 ="<<R1<<" z1 ="<<z1);
+
+  //now order the found values
+  double r_temp, z_temp;
+  if (R1>R2) { r_temp=R1; R1=R2; R2=r_temp; } //R1 - smaller one
+  if (z1<z2) { z_temp=z1; z1=z2; z2=z_temp; } //z1 - bigger one
+
+  if (R1==R2 || z1==z2) ATH_MSG_ERROR ("[punch-though] Bug in propagation calculation! R1="<<R1<<" R2 = "<<R2<<" z1="<<z1<<" z2= "<<z2 );
+  else 			ATH_MSG_DEBUG ("calo-MS boundary coordinates: R1="<<R1<<" R2 = "<<R2<<" z1="<<z1<<" z2= "<<z2);
+
+  ATH_MSG_INFO( "punchthrough initialization is successful" );
+  return StatusCode::SUCCESS;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+StatusCode ISF::PunchThroughTool::finalize()
+{
+  ATH_MSG_INFO( "[punchthrough] finalize() successful" );
+
+  // close the file with the lookuptable
+  m_fileLookupTable->Close();
+
+  return StatusCode::SUCCESS;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+const ISF::ISFParticleContainer* ISF::PunchThroughTool::computePunchThroughParticles(const ISF::ISFParticle &isfp) const
+{
+  ATH_MSG_DEBUG( "[ punchthrough ] starting punch-through simulation"); 
+
+  // reset the output particle collection
+  m_isfpCont = new ISF::ISFParticleContainer();
+
+  // reset the parent GenEvent
+  m_parentGenEvt = 0;
+
+  // store the initial particle state locally
+  m_initPs = &isfp;
+
+  ATH_MSG_VERBOSE("[ GeoIDSvc ] position of the input particle: r"<<m_initPs->position().perp()<<" z= "<<m_initPs->position().z() );
+  //if not on ID surface - don't simulate
+
+  if ( m_geoIDSvc->inside(m_initPs->position(),AtlasDetDescr::fAtlasID) != 1)  
+  { 
+    ATH_MSG_DEBUG("[ GeoIDSvc ] input particle position is not on reference surface -> no punch-through simulation");
+    return 0;
+  }	
+
+  //check if it points to the calorimeter - if not, don't simulate
+
+  if ( m_geoIDSvc->identifyNextGeoID(*m_initPs) != AtlasDetDescr::fAtlasCalo) 
+  {
+    ATH_MSG_VERBOSE ("[ GeoIDSvc ] input particle doesn't point to calorimeter"<< "Next GeoID: "<<m_geoIDSvc->identifyNextGeoID(*m_initPs) );
+    return 0;
+  }
+  
+  // check if the particle's pdg is registered as a punch-through-causing type
+  {
+    std::vector<int>::const_iterator pdgIt    = m_pdgInitiators.begin();
+    std::vector<int>::const_iterator pdgItEnd = m_pdgInitiators.end();
+    // loop over all known punch-through initiators
+    for ( ; pdgIt != pdgItEnd; ++pdgIt)
+    {   if (abs(m_initPs->pdgCode()) == *pdgIt) break; }
+
+    // particle will not cause punch-through -> bail out
+    if (pdgIt == pdgItEnd) 
+    {
+      ATH_MSG_DEBUG("[ punchthrough ] particle is not registered as punch-through initiator. Dropping it in the calo.");
+    return 0;
+    }
+  }
+
+  //if initial particle is on ID surface, points to the calorimeter and is a punch-through initiator
+ 
+  // store initial particle mass
+  double mass = m_initPs->mass();
+  //store its barcode
+  m_primBC = m_initPs->barcode();
+  // now store some parameters from the given particle locally
+  // in this class
+  //  -> the energy
+  m_initEnergy = sqrt( m_initPs->momentum().mag2() + mass*mass );
+  //  -> get geometrical properties
+  //  -> the pseudorapidity eta
+  m_initEta = m_initPs->position().eta();
+  //  -> the angle theta
+  m_initTheta = m_initPs->position().theta();
+  //  -> the azimutal angle phi
+  m_initPhi = m_initPs->position().phi();
+
+  // this is the place where the magic is done:
+  // test for each registered punch-through pdg if a punch-through
+  // occures and create these particles
+  // -> therefore loop over all registered pdg ids
+  std::map<int,PunchThroughParticle*>::const_iterator it;
+  // to keep track of the correlated particles which were already simulated:
+  // first int is pdg, second int is number of particles created
+  std::map<int, int> corrPdgNumDone;
+
+  // loop over all particle pdgs
+  for ( it = m_particles.begin(); it != m_particles.end(); ++it ) 
+  {
+    // the pdg that is currently treated
+    int doPdg = it->first;
+    // get the current particle's correlated pdg
+    int corrPdg = it->second->getCorrelatedPdg();
+
+    // if there is a correlated particle type to this one
+    if (corrPdg) 
+    {
+      // find out if the current pdg was already simulated
+      std::map<int,int>::iterator pos = corrPdgNumDone.find(doPdg);
+      // if the current pdg was not simulated yet, find out if
+      // it's correlated one was simulated
+      if ( pos == corrPdgNumDone.end() ) pos = corrPdgNumDone.find(corrPdg);
+
+      // neither this nor the correlated particle type was simulated
+      // so far:
+      if ( pos == corrPdgNumDone.end() ) 
+      {
+        // -> roll a dice if we create this particle or its correlated one
+        if ( CLHEP::RandFlat::shoot(m_randomEngine) > 0.5 ) doPdg = corrPdg;
+        // now create the particles with the given pdg and note how many
+        // particles of this pdg are created
+        corrPdgNumDone[doPdg] = getAllParticles(doPdg);
+      }
+
+      // one of the two correlated particle types was already simulated
+      // 'pos' points to the already simulated one
+      else 
+      {
+        // get the pdg of the already simulated particle and the number
+        // of these particles that were created
+        int donePdg = pos->first;
+        int doneNumPart = pos->second;
+        // set the pdg of the particle type that will be done
+        if (donePdg == doPdg) doPdg = corrPdg;
+
+        // now create the correlated particles
+        getCorrelatedParticles(doPdg, doneNumPart);
+        // note: no need to take note, that this particle type is now simulated,
+        // since this is the second of two correlated particles, which is
+        // simulated and we do not have correlations of more than two particles.
+      }
+
+    // if no correlation for this particle
+    // -> directly create all particles with the current pdg
+    } 
+    else getAllParticles(doPdg);
+
+  } // for-loop over all particle pdgs
+
+  if (m_isfpCont->size() > 0)  ATH_MSG_DEBUG( "[ punchthrough ] returning ISFparticle vector , size: "<<m_isfpCont->size() );
+
+  return m_isfpCont;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+int ISF::PunchThroughTool::getAllParticles(int pdg, int numParticles) const
+{
+  // first check if the ISF particle vector already exists
+  if (!m_isfpCont)    m_isfpCont = new ISFParticleContainer();
+  
+  // get the current particle
+  PunchThroughParticle *p = m_particles[pdg];
+
+  // if no number of particles (=-1) was handed over as an argument
+  //  -> get the number of particles from the pdf
+  if ( numParticles < 0 ) 
+  {
+    // prepare the function arguments for the PDFcreator class
+    std::vector<double> parameters;
+    parameters.push_back( m_initEnergy );
+    parameters.push_back( fabs(m_initEta) );
+    // the maximum number of particles which should be produced
+    // if no maximum number is given, this is -1
+    int maxParticles = p->getMaxNumParticles();
+
+    // get the right number of punch-through particles
+    // and ensure that we do not create too many particles
+    do 
+    { 
+      numParticles = lround( p->getNumParticlesPDF()->getRand(parameters, true) );
+      // scale the number of particles if requested
+      numParticles = lround( numParticles *= p->getNumParticlesFactor() );
+    } 
+    while ( (maxParticles >= 0.) && (numParticles > maxParticles) );
+  }
+
+  ATH_MSG_VERBOSE("[ punchthrough ] adding " << numParticles << " punch-through particles with pdg " << pdg);
+
+  // now create the exact number of particles which was just computed before
+  double energyRest = m_initEnergy;
+  double minEnergy = p->getMinEnergy();
+  int numCreated = 0;
+
+  for ( numCreated = 0; (numCreated < numParticles) && (energyRest > minEnergy); numCreated++ ) 
+  {
+    // create one particle which fullfills the right energy distribution
+    ISF::ISFParticle *par = getOneParticle(pdg, energyRest);
+
+    // if something went wrong
+    if (!par) 
+    {
+      ATH_MSG_ERROR("[ punchthrough ] something went wrong while creating punch-through particles");
+      return StatusCode::FAILURE;
+    }
+
+    // get the energy of the particle which was just created
+    double restMass = m_particleDataTable->particle(abs(pdg))->mass();
+    double curEnergy = sqrt(par->momentum().mag2() + restMass*restMass);
+
+    // calculate the maximum energy to be available for all
+    // following punch-through particles created
+    energyRest -= curEnergy;
+
+    // add this ISFparticle to the vector
+    m_isfpCont->push_back( par );
+  }
+
+  // the number of particles which was created is numCreated
+  return (numCreated);
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+int ISF::PunchThroughTool::getCorrelatedParticles(int pdg, int corrParticles) const
+{
+  // get the PunchThroughParticle class
+  PunchThroughParticle *p = m_particles[pdg];
+
+  // (1.) decide if we do correlation or not
+  double rand = CLHEP::RandFlat::shoot(m_randomEngine)
+                *(p->getFullCorrelationEnergy()-p->getMinCorrelationEnergy())
+                + p->getMinCorrelationEnergy();
+  if ( m_initEnergy < rand ) 
+  {
+    // here we do not do correlation
+    return getAllParticles(pdg);
+  }
+
+  // (2.) if this point is reached, we do correlation
+  // decide which 2d correlation histogram to use
+  double *histDomains = p->getCorrelationHistDomains();
+  TH2F *hist2d = 0;
+  // compute the center values of the lowE and highE
+  // correlation histogram domains
+  if ( m_initEnergy <  histDomains[1]) 
+  {
+    // initial energy lower than border between lowEnergy and highEnergy histogram domain
+    //  --> choose lowEnergy correlation histogram
+    hist2d = p->getCorrelationLowEHist();
+  } 
+  else  
+  {
+    double rand = CLHEP::RandFlat::shoot(m_randomEngine)*(histDomains[2]-histDomains[1])
+                          + histDomains[1];
+    hist2d = ( m_initEnergy < rand) ? p->getCorrelationLowEHist()
+                                    : p->getCorrelationHighEHist();
+  }
+
+  // get the correlation 2d histogram
+
+  // now find out where on the x-axis the the bin for number of
+  // correlated particles is
+  Int_t xbin = hist2d->GetXaxis()->FindFixBin(corrParticles);
+  int numParticles = 0;
+  int maxParticles = p->getMaxNumParticles();
+  // now the distribution along the y-axis is a PDF for the number
+  // of 'pdg' particles
+  do 
+  {
+    double rand = CLHEP::RandFlat::shoot(m_randomEngine);
+    double sum = 0.;
+    for ( int ybin = 1; ybin <= hist2d->GetNbinsY(); ybin++ ) 
+    {
+      sum += hist2d->GetBinContent(xbin, ybin);
+      // check if we choose the current bin or not
+      if ( sum >= rand ) 
+      {
+        numParticles = ybin - 1;
+        break;
+      }
+    }
+    // scale the number of particles is requested
+    numParticles = lround( numParticles * p->getNumParticlesFactor() );
+  } 
+  while ( (maxParticles >= 0.) && (numParticles > maxParticles) );
+
+  // finally create this exact number of particles
+  return getAllParticles(pdg, numParticles);
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+ISF::ISFParticle *ISF::PunchThroughTool::getOneParticle(int pdg, double maxEnergy) const 
+{
+  // get a local copy of the needed punch-through particle class
+  PunchThroughParticle *p = m_particles[pdg];
+
+  // (1.) decide if we create a particle or an anti-particle
+  int anti = 1;
+  if ( p->getdoAnti() ) 
+  {
+    // get a random-value
+    double rand = CLHEP::RandFlat::shoot(m_randomEngine);
+    // 50/50 chance to be a particle or its anti-particle
+    if (rand > 0.5) anti = -1;
+  }
+
+  // (2.) get the right punch-through distributions
+  // prepare the function arguments for the PDFcreator class
+  std::vector<double> parInitEnergyEta;
+  parInitEnergyEta.push_back( m_initEnergy );
+  parInitEnergyEta.push_back( fabs(m_initEta) );
+  
+  // (2.1) get the energy 
+  double energy = p->getExitEnergyPDF()->getRand(
+      parInitEnergyEta, false, p->getMinEnergy(), maxEnergy/p->getEnergyFactor() );
+  energy *= p->getEnergyFactor(); // scale the energy if requested
+
+  // set up the new parameters for the next PDFcreator::getRand calls
+  std::vector<double> parExitEnergyInitEta;
+  parExitEnergyInitEta.push_back( energy );
+  parExitEnergyInitEta.push_back( fabs(m_initEta) );
+
+  // (2.2) get the particles delta theta relative to the incoming particle
+   double theta = 0;
+  // loop to keep theta within range [0,PI]
+  do 
+  {
+    // get random value
+    double deltaTheta = p->getExitDeltaThetaPDF()->getRand(
+        parExitEnergyInitEta, false );
+    // decide if delta positive/negative
+    deltaTheta *=  ( CLHEP::RandFlat::shoot(m_randomEngine) > 0.5 ) ? 1. : -1.;
+    // calculate the exact theta value of the later created
+    // punch-through particle
+    theta = m_initTheta + deltaTheta*p->getPosAngleFactor();
+  } 
+  while ( (theta > M_PI) || (theta < 0.) );
+
+  // (2.3) get the particle's delta phi relative to the incoming particle
+
+  double deltaPhi = p->getExitDeltaPhiPDF()->getRand(
+                                  parExitEnergyInitEta, false );
+  deltaPhi *=  ( CLHEP::RandFlat::shoot(m_randomEngine) > 0.5 ) ? 1. : -1.;
+
+  // keep phi within range [-PI,PI]
+  double phi = m_initPhi + deltaPhi*p->getPosAngleFactor();
+  while ( fabs(phi) > 2*M_PI) phi /= 2.;
+  while (phi >  M_PI) phi -= 2*M_PI;
+  while (phi < -M_PI) phi += 2*M_PI;
+
+  // set up the new parameters for the next PDFcreator::getRand calls
+  std::vector<double> parExitEnergyExitEta;
+  parExitEnergyExitEta.push_back( energy );
+  parExitEnergyExitEta.push_back( -log(tan(theta/2.)) );
+
+  // (2.4) get the particle momentum delta theta, relative to its position
+  //
+  // loop to keep momTheta within range [0,PI]
+
+  double momTheta = 0.;
+  do 
+  {
+    // get random value
+    double momDeltaTheta = p->getMomDeltaThetaPDF()->getRand(
+                                    parExitEnergyExitEta, false );
+    // decide if delta positive/negative
+    momDeltaTheta *=  ( CLHEP::RandFlat::shoot(m_randomEngine) > 0.5 ) ? 1. : -1.;
+    // calculate the exact momentum theta value of the later created
+    // punch-through particle
+    momTheta = theta + momDeltaTheta*p->getMomAngleFactor();
+  } 
+  while ( (momTheta > M_PI) || (momTheta < 0.) );
+
+  // (2.5) get the particle momentum delta phi, relative to its position
+
+  double momDeltaPhi = p->getMomDeltaPhiPDF()->getRand(
+                                  parExitEnergyExitEta, false );
+  momDeltaPhi *=  ( CLHEP::RandFlat::shoot(m_randomEngine) > 0.5 ) ? 1. : -1.;
+
+  double momPhi = phi + momDeltaPhi*p->getMomAngleFactor();
+  // keep momPhi within range [-PI,PI]
+  while ( fabs(momPhi) > 2*M_PI) momPhi /= 2.;
+  while (momPhi >  M_PI) momPhi -= 2*M_PI;
+  while (momPhi < -M_PI) momPhi += 2*M_PI;
+
+  //assign barcodes to the produced particles
+  m_processCode = 0;
+  m_secBC = m_barcodeSvc->newSecondary( m_primBC, m_processCode);
+
+  // (**) finally create the punch-through particle as a ISFParticle
+
+  ISF::ISFParticle *par = createExitPs( pdg*anti, energy, theta, phi, momTheta, momPhi);
+
+  return par;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+StatusCode
+ISF::PunchThroughTool::registerParticle(int pdg, bool doAntiparticle,
+    double minEnergy, int maxNumParticles, double numParticlesFactor,
+    double energyFactor, double posAngleFactor, double momAngleFactor)
+{
+  // read in the data needed to construct the distributions for the number of punch-through particles
+ 
+  // (1.) get the distribution function for the number of punch-through particles
+  PDFcreator *pdf_num = readLookuptablePDF(pdg, "NumExitPDG");
+  if (!pdf_num ) return StatusCode::FAILURE; // return error if something went wrong
+
+  // (2.) get the PDF for the punch-through energy
+  PDFcreator *pdf_energy = readLookuptablePDF(pdg, "ExitEnergyPDG");
+  if (!pdf_energy) 
+  {
+    delete pdf_num;
+    return StatusCode::FAILURE; // return error if something went wrong
+  }
+
+  // (3.) get the PDF for the punch-through particles difference in
+  //      theta compared to the incoming particle
+  PDFcreator *pdf_theta = readLookuptablePDF(pdg, "ExitDeltaThetaPDG");
+  if (!pdf_theta) 
+  {
+    delete pdf_num; delete pdf_energy;
+    return StatusCode::FAILURE;
+  }
+
+  // (4.) get the PDF for the punch-through particles difference in
+  //      phi compared to the incoming particle
+  PDFcreator *pdf_phi = readLookuptablePDF(pdg, "ExitDeltaPhiPDG");
+  if (!pdf_phi) 
+  {
+    delete pdf_num; delete pdf_energy; delete pdf_theta;
+    return StatusCode::FAILURE;
+  }
+
+  // (5.) get the PDF for the punch-through particle momentum delta theta angle
+  PDFcreator *pdf_momTheta = readLookuptablePDF(pdg, "MomDeltaThetaPDG");
+  if (!pdf_momTheta) 
+  {
+    delete pdf_num; delete pdf_energy; delete pdf_theta; delete pdf_phi;
+    return StatusCode::FAILURE;
+  }
+
+  // (6.) get the PDF for the punch-through particle momentum delta phi angle
+  PDFcreator *pdf_momPhi = readLookuptablePDF(pdg, "MomDeltaPhiPDG");
+  if (!pdf_momPhi) 
+  {
+    delete pdf_num; delete pdf_energy; delete pdf_theta; delete pdf_phi; delete pdf_momTheta;
+    return StatusCode::FAILURE;
+  }
+
+  // (7.) now finally store all this in the right std::map
+  PunchThroughParticle *particle = new PunchThroughParticle(pdg, doAntiparticle);
+  particle->setNumParticlesPDF(pdf_num);
+  particle->setExitEnergyPDF(pdf_energy);
+  particle->setExitDeltaThetaPDF(pdf_theta);
+  particle->setExitDeltaPhiPDF(pdf_phi);
+  particle->setMomDeltaThetaPDF(pdf_momTheta);
+  particle->setMomDeltaPhiPDF(pdf_momPhi);
+
+  // (8.) set some additional particle and simulation properties
+  double restMass = m_particleDataTable->particle(abs(pdg))->mass();
+  minEnergy = ( minEnergy > restMass ) ? minEnergy : restMass;
+  particle->setMinEnergy(minEnergy);
+  particle->setMaxNumParticles(maxNumParticles);
+  particle->setNumParticlesFactor(numParticlesFactor);
+  particle->setEnergyFactor(energyFactor);
+  particle->setPosAngleFactor(posAngleFactor);
+  particle->setMomAngleFactor(momAngleFactor);
+
+  // (9.) insert this PunchThroughParticle instance into the std::map class member
+  m_particles[pdg] = particle;
+
+  return StatusCode::SUCCESS;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+StatusCode ISF::PunchThroughTool::registerCorrelation(int pdgID1, int pdgID2,
+    double minCorrEnergy, double fullCorrEnergy)
+{
+  // find the given pdgs in the registered particle ids
+  std::map<int, PunchThroughParticle*>::iterator location1 = m_particles.find(pdgID1);
+  std::map<int, PunchThroughParticle*>::iterator location2 = m_particles.find(pdgID2);
+
+  // if at least one of the given pdgs was not registered yet -> return an error
+  if ( (location1 == m_particles.end()) || (location2 == m_particles.end()) )
+    return StatusCode::FAILURE;
+  
+  // now look for the correlation histograms
+  std::stringstream name;
+  name << "NumExitCorrelations/x_PDG" << abs(pdgID1) << "__y_PDG" << abs(pdgID2) << "__lowE";
+  TH2F *hist1_2_lowE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
+  name.str("");
+  name << "NumExitCorrelations/x_PDG" << abs(pdgID1) << "__y_PDG" << abs(pdgID2) << "__highE";
+  TH2F *hist1_2_highE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
+  name.str("");
+  name << "NumExitCorrelations/x_PDG" << abs(pdgID2) << "__y_PDG" << abs(pdgID1) << "__lowE";
+  TH2F *hist2_1_lowE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
+  name.str("");
+  name << "NumExitCorrelations/x_PDG" << abs(pdgID2) << "__y_PDG" << abs(pdgID1) << "__highE";
+  TH2F *hist2_1_highE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
+  // check if the histograms exist
+  if ( (!hist1_2_lowE) || (!hist2_1_lowE) || (!hist1_2_highE) || (!hist2_1_highE) ) 
+  {
+    ATH_MSG_ERROR("[ punchthrough ] unable to retrieve the correlation data for PDG IDs " << pdgID1 <<  " and " << pdgID2);
+    return StatusCode::FAILURE;
+  }
+
+  // TODO: if only one of the two histograms exists, create the other one
+  //       by mirroring the data
+ 
+  double lowE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(), "elow_");
+  double midE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(), "ehigh_");
+  //TODO: check if the same:
+  // double midE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(), "elow_");
+  double upperE = getFloatAfterPatternInStr( hist1_2_highE->GetTitle(), "ehigh_");
+  // now store the correlation either way  id1->id2 and id2->id1
+  m_particles[pdgID1]->setCorrelation(pdgID2, hist2_1_lowE, hist2_1_highE,
+                                      minCorrEnergy, fullCorrEnergy,
+                                      lowE, midE, upperE);
+
+  m_particles[pdgID2]->setCorrelation(pdgID1, hist1_2_lowE, hist1_2_highE,
+                                      minCorrEnergy, fullCorrEnergy,
+                                      lowE, midE, upperE);
+  return StatusCode::SUCCESS;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *======================================================================*/
+
+ISF::PDFcreator *ISF::PunchThroughTool::readLookuptablePDF(int pdg, std::string folderName)
+{
+  // will hold the PDFcreator class which will be returned at the end
+  // this will store the probability density functions for the number of punch-through particles
+  // (as functions of energy & eta of the incoming particle)
+  PDFcreator *pdf = 0;
+
+  // (1.) retrieve the distribution function
+  std::stringstream name;
+  name << folderName << pdg << "/function";
+  TF1 *func = (TF1*)m_fileLookupTable->Get(name.str().c_str());
+  if (! func ) 
+  {
+    ATH_MSG_ERROR("[ punchthrough ] unable to retrieve the PDF (" << folderName << ") from the lookuptable" );
+    return 0;
+  }
+  // store this function in the PDFcreator class
+  pdf = new PDFcreator(func, m_randomEngine);
+
+  // (2.) get this function maximum and minimum
+  std::stringstream namemin, namemax;
+  namemin << folderName << pdg << "/randmin";
+  TH1 *randmin = (TH1*)m_fileLookupTable->Get(namemin.str().c_str());
+  namemax << folderName << pdg << "/randmax";
+  TH1 *randmax = (TH1*)m_fileLookupTable->Get(namemax.str().c_str());
+
+  if ( !(randmin && randmax) ) 
+  {
+    ATH_MSG_ERROR("[ punchthrough ] unable to retrieve the PDF boundaries (" << folderName << ") from the lookuptable" );
+    delete pdf;
+    return 0;
+  }
+
+  // store this histogram in the PDFcreator class
+  pdf->setRange( randmin, randmax);
+
+  // (3.) get the parameters for the just received distribution function (stored in TH2F histograms)
+  for (int par = 0; par < func->GetNpar(); par++) 
+  {
+    // prepare the name of the histogram in the file
+    name.str("");
+    name << folderName << pdg<< "/parameter" << par;
+
+    // get the histogram from the file
+    TH1 *hist = (TH1*)m_fileLookupTable->Get(name.str().c_str());
+
+    // if histogram does not exist -> error!
+    if(! hist) 
+    {
+      ATH_MSG_ERROR( "[ punchthrough ] unable to retrieve all parameters for the distribution ("<< folderName << pdg << ")" );
+      delete pdf;
+      return 0;
+    }
+
+    // add this histogram to the PDFcreator class
+    pdf->addPar( hist );
+  }
+
+  return pdf;
+}
+
+/* =========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=========================================================================*/
+
+ISF::ISFParticle* ISF::PunchThroughTool::createExitPs( int pdg,
+    double energy, double theta, double phi,double momTheta, double momPhi) const
+{
+  // the intersection point with Calo-MS surface
+
+  Amg::Vector3D pos = propagator(theta,phi);
+
+  // set up the real punch-through particle at this position
+  // set up the momentum vector of this particle as a GlobalMomentum
+  // by using the given energy and mass of the particle and also using
+  // the given theta and phi
+
+  Amg::Vector3D mom;
+  double mass = m_particleDataTable->particle(abs(pdg))->mass();
+  Amg::setRThetaPhi( mom, sqrt(energy*energy - mass*mass), momTheta, momPhi);
+
+  double charge = m_particleDataTable->particle(abs(pdg))->charge();
+  // since the PDT table only has abs(PID) values for the charge
+  charge *= (pdg > 0.) ?  1. : -1.;
+
+  double pTime = 0;  /** @TODO: fix */
+
+  ISF::ISFParticle* finalPar = new ISF::ISFParticle (pos, mom, mass, charge, pdg, pTime, *m_initPs, m_secBC);
+  finalPar->setNextGeoID( AtlasDetDescr::fAtlasMS);
+
+  // return the punch-through particle
+  return finalPar;
+}
+
+/*=========================================================================
+ *  DESCRIPTION OF FUNCTION:
+ *  ==> see headerfile
+ *=======================================================================*/
+
+double ISF::PunchThroughTool::getFloatAfterPatternInStr(const char *cstr, const char *cpattern)
+{
+  double num = 0.;
+
+  std::string str( cstr);
+  std::string pattern( cpattern);
+  size_t pos = str.find(cpattern);
+
+  if ( pos == std::string::npos) 
+  {
+    ATH_MSG_WARNING("[ punchthrough ] unable to retrieve floating point number from string");
+    return -999999999999.;
+  }
+
+  std::istringstream iss( cstr+pos+pattern.length());
+  iss >> std::dec >> num;
+
+  return num;
+}
+
+Amg::Vector3D ISF::PunchThroughTool::propagator(double theta,double phi) const
+{
+  // phi, theta - direction of the punch-through particle coming into calo
+  //particle propagates inside the calorimeter along the straight line
+  //coordinates of this particles when exiting the calo (on calo-MS boundary)
+
+  double x, y, z, r;
+
+  // cylinders border angles
+  double theta1 = atan (R1/z1);
+  double theta2 = atan (R1/z2);
+  double theta3 = atan (R2/z2);
+  //where is the particle
+
+  if (theta >= 0 && theta < theta1)
+  {
+    z = z1;
+    r = fabs (z1*tan(theta));
+  }
+  else if (theta >= theta1 && theta < theta2)
+  {
+    z = R1/tan(theta);
+    r = R1;
+  }
+  else if (theta >= theta2 && theta < theta3)
+  {
+    z = z2;
+    r = fabs(z2*tan(theta));;
+  }
+  else if (theta >= theta3 && theta < (TMath::Pi()-theta3) )
+  { 
+    z = R2/tan(theta);
+    r = R2;
+  }
+  else if (theta >= (TMath::Pi()-theta3) && theta < (TMath::Pi()-theta2) )
+  {
+    z = -z2;
+    r = fabs(z2*tan(theta));
+  }
+  else if (theta >= (TMath::Pi()-theta2) && theta < (TMath::Pi()-theta1) )
+  {
+    z = R1/tan(theta);
+    r = R1;
+  }
+  else if (theta >= (TMath::Pi()-theta1) && theta <= TMath::Pi() )
+  {
+    z = -z1;
+    r = fabs(z1*tan(theta));
+  }
+
+  //parallel universe
+  else 
+  {
+    ATH_MSG_WARNING ( "Given theta angle is incorrect, setting particle position to (0, 0, 0)");
+    x = 0.0; y = 0.0; z = 0.0; r = 0.0;
+  }
+  
+  x = r*cos(phi);
+  y = r*sin(phi);
+  Amg::Vector3D pos(x, y, z);
+  
+  ATH_MSG_DEBUG("position of produced punch-through particle: x = "<< x <<" y = "<< y <<" z = "<< z<<" r = "<< pos.perp() <<"sqrt(x^2+y^2) = "<< sqrt(x*x+y*y) );
+  ATH_MSG_DEBUG("GeoID thinks: Calo: "<< m_geoIDSvc->inside(pos, AtlasDetDescr::fAtlasCalo) <<" MS: "<< m_geoIDSvc->inside(pos,AtlasDetDescr::fAtlasMS));
+
+  return pos;
+}
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/components/ISF_PunchThroughTools_entries.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/components/ISF_PunchThroughTools_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d360f7ce0f163c34b948ac306e24a8a5252b7d38
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/components/ISF_PunchThroughTools_entries.cxx
@@ -0,0 +1,8 @@
+#include "GaudiKernel/DeclareFactoryEntries.h"
+#include "ISF_PunchThroughTools/PunchThroughTool.h"
+
+DECLARE_NAMESPACE_TOOL_FACTORY( ISF,PunchThroughTool)
+DECLARE_FACTORY_ENTRIES( ISF_PunchThroughTools ) {
+  DECLARE_NAMESPACE_TOOL( ISF,PunchThroughTool)
+}
+
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/components/ISF_PunchThroughTools_load.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/components/ISF_PunchThroughTools_load.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..428a49e65990035e8a7c73da3843dd7b59500657
--- /dev/null
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_PunchThroughTools/src/components/ISF_PunchThroughTools_load.cxx
@@ -0,0 +1,5 @@
+
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES( ISF_PunchThroughTools )
+