diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/HadIntProcessorParametric.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/HadIntProcessorParametric.h
index 763bd4eeae23eac05bc0e4a14b273b476ecbbdc2..c00aba52724335d6f93a6ab6ae71bd5f6c2ada0b 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/HadIntProcessorParametric.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/HadIntProcessorParametric.h
@@ -75,24 +75,26 @@ namespace iFatras {
       StatusCode finalize();
 
       /** interface for processing of the nuclear interactions */
-      bool hadronicInteraction(const Trk::TrackParameters& parm, double p, double E,
+      bool hadronicInteraction(const Amg::Vector3D& position, const Amg::Vector3D& momentum, 
+			       double p, double E, double charge,
                                const Trk::MaterialProperties& mprop, double pathCorrection,
                                Trk::ParticleHypothesis particle=Trk::pion) const;
 
       /** interface for processing of the presampled nuclear interaction */                           
       bool recordHadState(double time, double p,
-         const Amg::Vector3D& vertex,
-         const Amg::Vector3D& particleDir,
-         Trk::ParticleHypothesis particle ) const;
+			  const Amg::Vector3D& vertex,
+			  const Amg::Vector3D& particleDir,
+			  Trk::ParticleHypothesis particle ) const;
 
-      bool doHadronicInteraction(double time,const Trk::TrackParameters& parm,
-				 const Trk::Material* ematprop,
+      bool doHadronicInteraction(double time, const Amg::Vector3D& position, const Amg::Vector3D& momentum, 
+				 const Trk::Material* emat,
 				 Trk::ParticleHypothesis particle,
 				 bool processSecondaries) const;
  
-      ISF::ISFParticleVector doHadIntOnLayer(const ISF::ISFParticle* parent, double time,const Trk::TrackParameters& parm,
-				 const Trk::MaterialProperties* ematprop,
-				 Trk::ParticleHypothesis particle) const;
+      ISF::ISFParticleVector doHadIntOnLayer(const ISF::ISFParticle* parent, double time,
+					     const Amg::Vector3D& position, const Amg::Vector3D& momentum, 
+					     const Trk::Material* emat,
+					     Trk::ParticleHypothesis particle) const;
  
    private:
       /** interface for calculation of absorption length */
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McBetheHeitlerEnergyLossUpdator.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McBetheHeitlerEnergyLossUpdator.h
deleted file mode 100755
index 3168e672184b1a2b8b3a9a22765b20347cd913fd..0000000000000000000000000000000000000000
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McBetheHeitlerEnergyLossUpdator.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*********************************************************************************
-			McBetheHeitlerEnergyLossUpdator.h  -  description
-			-------------------------------------------------
-begin                : Wednesday 28th June 2006
-author               : atkinson
-email                : Tom.Atkinson@cern.ch
-decription           : Class for updating energy loss based on the Bethe-Heitler
-		       distribution
-*********************************************************************************/
-
-#ifndef ISF_Fatras_McBetheHeitlerEnergyLossUpdator_H
-#define ISF_Fatras_McBetheHeitlerEnergyLossUpdator_H
-
-// Gaudi & Athena
-#include "AthenaBaseComps/AthAlgTool.h"
-#include "GaudiKernel/ServiceHandle.h"
-#include "AthenaKernel/IAtRndmGenSvc.h"
-// Trk
-#include "TrkExInterfaces/IEnergyLossUpdator.h"
-#include "TrkEventPrimitives/ParticleHypothesis.h"
-#include "TrkEventPrimitives/PropDirection.h"
-
-namespace Trk{
-  class MaterialProperties;
-  class EnergyLoss;
-}
-
-namespace iFatras{
-	
-class McBetheHeitlerEnergyLossUpdator : public AthAlgTool, virtual public Trk::IEnergyLossUpdator {
-   
- public:	
-	
-  /** Constructor with AlgTool parameters */
-  McBetheHeitlerEnergyLossUpdator( const std::string&, const std::string&, const IInterface* );
-  
-  /** Destructor */
-  ~McBetheHeitlerEnergyLossUpdator();
-  
-  /** AlgTool initialise method */
-  StatusCode initialize();
-  
-  /** AlgTool finalize method */
-  StatusCode finalize();
-  
-  /** dEdx method - not used */
-  double dEdX( const Trk::MaterialProperties& materialProperties, 
-	       double momentum, 
-	       Trk::ParticleHypothesis particleHypothesis = Trk::electron ) const;
-  
-  /** Method to determine the change in q/p and the variance */
-  Trk::EnergyLoss* energyLoss( const Trk::MaterialProperties& materialProperties,
-                               double momentum,
-                               double pathCorrection,
-                               Trk::PropDirection direction = Trk::alongMomentum,
-                               Trk::ParticleHypothesis particleHypothesis = Trk::electron,
-                               bool mpv = false) const;
-                               
-  /** Method to recalculate Eloss values for the fit setting an elossFlag using as an input
-        the detailed Eloss information Calorimeter energy, error momentum and momentum error */
-  
-  Trk::EnergyLoss* updateEnergyLoss( Trk::EnergyLoss*, double, double, double, double, int&) const override { return 0; }
-  
-   /** Routine to calculate X0 and Eloss scale factors for the Calorimeter and Muon System */
-   void getX0ElossScales(int, double, double, double&, double& ) const override {}                               
-  
- private:
-  
-  /** Private method to compute the Bethe-Heitler PDF */
-  std::vector<double> betheHeitlerPDF( double pathLength ) const;
-  
-  ServiceHandle<IAtRndmGenSvc> m_rndmGenSvc;       //!< Random number generator
-  CLHEP::HepRandomEngine*             m_randomEngine;
-  std::string                  m_randomEngineName; //!< Name of the random number stream
-
-  mutable std::vector<double>          m_pdf;
-  mutable double                       m_cashedPathLength;
-  int                                  m_numberPointsInPDF;
-
-  double                               m_scaleFactor;    //!< the one free parameter to scale
-     
-  static Trk::ParticleMasses    s_particleMasses;         //!< struct of Particle masses   
-
-};
- 
-} // end iFatras namespace
-
-inline double iFatras::McBetheHeitlerEnergyLossUpdator::dEdX( const Trk::MaterialProperties&, double, Trk::ParticleHypothesis ) const
-{ return 0.; }
-
-#endif
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McEnergyLossUpdator.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McEnergyLossUpdator.h
index 446f7d2a539570d4854bd1258cc92755d5c02dac..c590e605e1803b0244395c10f08e5334064cd136 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McEnergyLossUpdator.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McEnergyLossUpdator.h
@@ -67,22 +67,20 @@ namespace iFatras{
                                  Trk::ParticleHypothesis particleHypothesis = Trk::pion,
                                  bool mpv=true) const override;
 
-  /** Method to recalculate Eloss values for the fit setting an elossFlag using as an input
-        the detailed Eloss information Calorimeter energy, error momentum and momentum error */
-  
+    /** Dummy methodes imposed by public interface - cleanup */
+    /** Method to recalculate Eloss values for the fit setting an elossFlag using as an input
+        the detailed Eloss information Calorimeter energy, error momentum and momentum error */ 
     Trk::EnergyLoss* updateEnergyLoss( Trk::EnergyLoss*, double, double, double, double, int&) const override { return 0; }
   
-   /** Routine to calculate X0 and Eloss scale factors for the Calorimeter and Muon System */
-   void getX0ElossScales(int, double, double, double&, double& ) const override {}
-
+    /** Routine to calculate X0 and Eloss scale factors for the Calorimeter and Muon System */
+    void getX0ElossScales(int, double, double, double&, double& ) const override {}
+    /** Dummy methods end here */
+     
  private:
   
    ToolHandle<IEnergyLossUpdator> m_energyLossUpdator;            //!< Pointer to the energy loss updator
    int                            m_energyLossDistribution;       //!< include energy loss straggling or not ( 0 == none, 1 == gauss, 2 == landau)
 
-   bool                           m_dedicatedElectronUpdator;     //!< boolean switch for use of a dedicated eloss updator
-   ToolHandle<IEnergyLossUpdator> m_elEnergyLossUpdator;          //!< Pointer to the energy loss updator - electrons
-
    /** Random Generator service  */
    ServiceHandle<IAtRndmGenSvc>                 m_rndGenSvc;
    /** Random engine  */
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.h
index 3dd8158fdef5a91aef69515f9224239966d93d74..1c73288f95ce74a98c2d0223b3b17aa49a0f9532 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.h
@@ -2,6 +2,7 @@
   Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 */
 
+
 ///////////////////////////////////////////////////////////////////
 // McMaterialEffectsEngine.h, (c) ATLAS Detector software
 ///////////////////////////////////////////////////////////////////
@@ -17,11 +18,12 @@
 
 // Trk
 #include "TrkExInterfaces/IMaterialEffectsEngine.h"
+#include "TrkExInterfaces/IEnergyLossUpdator.h"
 #include "TrkExUtils/ExtrapolationCell.h"
-#include "TrkExUtils/MaterialInteraction.h"
 #include "TrkEventPrimitives/PropDirection.h"
 #include "TrkParameters/TrackParameters.h"
 #include "TrkExUtils/MaterialUpdateMode.h"
+#include "TrkEventPrimitives/PdgToParticleHypothesis.h"
 
 // ISF
 #include "ISF_Event/ITruthIncident.h"
@@ -32,129 +34,190 @@
 
 class StoreGateSvc;
 
-namespace Trk {
+namespace Trk{
   class EnergyLoss;
   class CylinderVolumeBounds;
-  class IEnergyLossUpdator;
-  class IMultipleScatteringUpdator;
   class TrackingGeometry;
   class ITrackingGeometrySvc;
 }
 
 namespace ISF {
-    class IParticleBroker;
-    class ISFParticle;
-    class ITruthSvc;
+  class IParticleBroker;
+  class ISFParticle;
+  class ITruthSvc;
 }
 
 namespace iFatras {
+
+  class IPhysicsValidationTool;
+  class IEnergyLossSampler;
+  class IMultipleScatteringSampler;
+  class IHadronicInteractionProcessor;
+  class IPhotonConversionSampler; 
+  class IParticleDecayHelper;
+  class IProcessSamplingTool;
   
   /** @class McMaterialEffectsEngine
-  
-      Updator for a track on a Trk::Layer, it extends the IMaterialEffectsEngine to 
-      be used inside the Extrapolator with an update based on a Random number.
-      
-      The McMaterialEffectsEngine uses both an extended EnergyLossUpdator
-      and the standard ATLAS MultipleScatteringUpdator configured for the Gaussian-Mixture-Model.
-
-      @author Andreas.Salzburger@cern.ch, Noemi.Calace@cern.ch
-   */
-   
-  class McMaterialEffectsEngine : public AthAlgTool, virtual public Trk::IMaterialEffectsEngine { 
-    public:      
-      /**AlgTool constructor for McMaterialEffectsEngine*/
-      McMaterialEffectsEngine(const std::string&,const std::string&,const IInterface*);
-      /**Destructor*/
-      virtual ~McMaterialEffectsEngine();
-       
-      /** AlgTool initailize method.*/
-      StatusCode initialize();
-      /** AlgTool finalize method */
-      StatusCode finalize();
-      
-      /** Updator interface (full update for a layer): 
-         given track parameters are deleted internally,
-         if no update has to be done, 
-         the pointer is returned
-        */ 
-      virtual Trk::ExtrapolationCode handleMaterial(Trk::ExCellCharged& ecCharged,
-						    Trk::PropDirection dir=Trk::alongMomentum,
-						    Trk::MaterialUpdateStage matupstage=Trk::fullUpdate) const;
-
-      virtual Trk::ExtrapolationCode handleMaterial(Trk::ExCellNeutral&,
-						    Trk::PropDirection,
-						    Trk::MaterialUpdateStage) const {return Trk::ExtrapolationCode::InProgress; }
-      
-   private:
-      
-      const Trk::TrackParameters* updateTrackParameters(const Trk::TrackParameters& parameters,
-							Trk::ExCellCharged& eCell,
-							Trk::PropDirection dir,
-							Trk::MaterialUpdateStage matupstage) const;
-      
-      double simulate_theta_space(double beta, double p,double dOverX0,double Z, double scale) const;
-      double * get_gaussian(double beta, double p,double dOverX0, double scale) const;
-      double * get_gaussmix(double beta, double p,double dOverX0,double Z, double scale) const;
-      double * get_semigauss(double beta,double p,double dOverX0,double Z, double scale) const;
-      double sim_gaussmix(double * scattering_params) const;
-      double sim_semigauss(double * scattering_params) const;
-
-      void ionize(const Trk::TrackParameters& parm, AmgVector(5)& updatedPar, double dInX0,
-		  Trk::PropDirection pdir, Trk::ParticleHypothesis particle ) const ;
-      
-      /** the private multiple scattering sigma calculation*/
-      double msSigma(double dInX0, double p,Trk::ParticleHypothesis particle) const;
-      
-      /** the private multiple Scattering update method, thetaMs is the projected random number*/
-      void multipleScatteringUpdate( const Trk::TrackParameters& parm,
-				     AmgVector(5)& parameters,
-				     double sigmaMSproj, double pathCorrection) const;
-                 
-      /** IEnergyLossUpdator */
-      bool                                         m_eLoss;
-      ToolHandle<Trk::IEnergyLossUpdator>          m_eLossUpdator;
       
-      /** IMultipleScatteringUpdator */
-      bool                                         m_ms;
-      ToolHandle<Trk::IMultipleScatteringUpdator>  m_msUpdator;
+      Mc Material effects engine for charged and neutral (fast track simulation) used inside the ExtrapolatorEngine. It extends the IMaterialEffectsEngine.
       
-      /** Minimum momentum cut */
-      double                                       m_minimumMomentum;
+      The McMaterialEffectsEngine uses both an extended EnergyLossSampler
+      and the standard ATLAS MultipleScatteringSampler configured for the Gaussian-Mixture-Model.
       
-      /** switch between MSUpdator and local parametrization */
-      bool                                         m_use_msUpdator;
-      
-      /** Switch to use reference material */
-      bool                                         m_referenceMaterial;
-      
-      /** Switch to use bending correction */
-      bool                                         m_bendingCorrection;
-
-      /** Random Generator service  */
-      ServiceHandle<IAtRndmGenSvc>                 m_rndGenSvc;
-      /** Random engine  */
-      CLHEP::HepRandomEngine*                      m_randomEngine;
-      std::string                                  m_randomEngineName;                   //!< Name of the random number stream
-      
-      mutable const Trk::TrackingGeometry*         m_trackingGeometry;                   //!< the tracking geometry owned by the navigator
-      ServiceHandle<Trk::ITrackingGeometrySvc>     m_trackingGeometrySvc;                //!< ToolHandle to the TrackingGeometrySvc
-      std::string                                  m_trackingGeometryName;               //!< default name of the TrackingGeometry      
-      
-      /** struct of Particle Masses */
-      Trk::ParticleMasses                         m_particleMasses;
-      
-      ServiceHandle<ISF::IParticleBroker>     m_particleBroker;
-      ServiceHandle<ISF::ITruthSvc>           m_truthRecordSvc;
-
-      /** cache incoming particle */
-      mutable const ISF::ISFParticle*         m_isp;
-
-      /** cache layer properties */
-      mutable const Trk::Layer*                             m_layer;
-      mutable const Trk::MaterialProperties*                m_matProp;                                                                              
-           
-  };
+      @author Andreas.Salzburger@cern.ch, Noemi.Calace@cern.ch
+  */
   
+  class McMaterialEffectsEngine : public AthAlgTool, virtual public Trk::IMaterialEffectsEngine { 
+  public:      
+    /**AlgTool constructor for McMaterialEffectsEngine*/
+    McMaterialEffectsEngine(const std::string&,const std::string&,const IInterface*);
+    /**Destructor*/
+    virtual ~McMaterialEffectsEngine();
+    
+    /** AlgTool initailize method.*/
+    StatusCode initialize();
+    /** AlgTool finalize method */
+    StatusCode finalize();
+    
+    /** charged extrapolation */
+    virtual Trk::ExtrapolationCode handleMaterial(Trk::ExCellCharged& ecCharged,
+						  Trk::PropDirection dir=Trk::alongMomentum,
+						  Trk::MaterialUpdateStage matupstage=Trk::fullUpdate) const;
+
+    /** charged extrapolation */
+    virtual Trk::ExtrapolationCode handleMaterial(Trk::ExCellNeutral& ecNeutral,
+						  Trk::PropDirection dir= Trk::alongMomentum,
+						  Trk::MaterialUpdateStage matupstage=Trk::fullUpdate) const;
+    
+  private:
+
+    template <class T> Trk::ExtrapolationCode handleMaterialT( Trk::ExtrapolationCell<T>& eCell,
+							       Trk::PropDirection dir=Trk::alongMomentum,
+							       Trk::MaterialUpdateStage matupstage=Trk::fullUpdate) const;
+    
+    Trk::ExtrapolationCode processMaterialOnLayer(const ISF::ISFParticle* isp,
+				Trk::ExCellCharged& eCell,
+				Trk::PropDirection dir,
+				float& mFraction) const;
+
+    Trk::ExtrapolationCode processMaterialOnLayer(const ISF::ISFParticle* isp,
+				Trk::ExCellNeutral& eCell,
+				Trk::PropDirection dir,
+				float& mFraction) const;
+
+    void multipleScatteringUpdate(const Trk::TrackParameters& pars,
+				  AmgVector(5)& parameters,
+				  double simTheta, 
+				  double num_deltaPhi) const;
+
+    void recordBremPhoton(const ISF::ISFParticle* parent,
+			  double time,
+			  double pElectron,
+			  double gammaE,
+			  const Amg::Vector3D& vertex,
+			  Amg::Vector3D& particleDir,Trk::ParticleHypothesis  ) const; 
+
+    void recordBremPhotonLay(const ISF::ISFParticle* parent,
+			     double time,
+			     double pElectron,
+			     double gammaE,
+			     const Amg::Vector3D& vertex,
+			     Amg::Vector3D& particleDir,Trk::ParticleHypothesis, 
+			     Trk::PropDirection dir,float mFraction ) const; 
+
+    ISF::ISFParticle* bremPhoton(const ISF::ISFParticle* parent,
+				 double time,
+				 double pElectron,
+				 double gammaE,
+				 const Amg::Vector3D& vertex,
+				 Amg::Vector3D& particleDir, Trk::ParticleHypothesis ) const; 
+    
+    void radiate(const ISF::ISFParticle* parent, AmgVector(5)& parm ,
+		 Trk::ExCellCharged& eCell, float pathlim, float mFr,Trk::PropDirection dir,float refX) const;
+    
+    /** IProcessSamplig */
+    ToolHandle<IProcessSamplingTool>             m_samplingTool;
+
+    /** IEnergyLossSampler */
+    bool                                             m_eLoss;
+    //ToolHandle<iFatras::IEnergyLossSampler>          m_eLossSampler;
+    ToolHandle<Trk::IEnergyLossUpdator>              m_eLossSampler;
+    /** Boolean switch for use of a dedicated eloss updator */
+    bool                                             m_dedicatedElectronSampler;     
+    /** Pointer to the energy loss sampler - electrons */
+    ToolHandle<iFatras::IEnergyLossSampler>          m_elEnergyLossSampler;          
+   
+    /** IMultipleScatteringSampler */
+    bool                                             m_ms;
+    ToolHandle<iFatras::IMultipleScatteringSampler>  m_msSampler;
+
+    /** Particle Decay */
+    ToolHandle<IParticleDecayHelper>             m_particleDecayHelper; 
+    
+    /** describe deflection parametric/do real deflection */
+    bool                                             m_parametricScattering;
+
+    /** use the relativistic hertz dipole for brem photon radiation */
+    bool                                             m_uniformHertzDipoleAngle;
+    
+    /** MCTruth process code for TruthIncidents created by this tool */
+    Barcode::PhysicsProcessCode                      m_processCode;
+     
+    /** Minimum momentum cut */
+    double                                           m_minimumMomentum;
+    
+    /** Minimum momentum for brem photons */
+    double                                           m_minimumBremPhotonMomentum;
+    
+    /** Create brem photons flag */
+    bool                                             m_createBremPhoton;
+     
+    /** Switch to use bending correction */
+    bool                                             m_bendingCorrection;
+
+    /** Random Generator service  */
+    ServiceHandle<IAtRndmGenSvc>                     m_rndGenSvc;
+    /** Random engine  */
+    CLHEP::HepRandomEngine*                          m_randomEngine;
+    /** Name of the random number stream */
+    std::string                                      m_randomEngineName;                 
+    
+    /** the tracking geometry owned by the navigator */
+    mutable const Trk::TrackingGeometry*             m_trackingGeometry;         
+    /** ToolHandle to the TrackingGeometrySvc */
+    ServiceHandle<Trk::ITrackingGeometrySvc>         m_trackingGeometrySvc;          
+    /** default name of the TrackingGeometry  */
+    std::string                                      m_trackingGeometryName;    
+    
+    /** struct of Particle Masses */
+    Trk::ParticleMasses                              m_particleMasses;
+    Trk::PdgToParticleHypothesis                     m_pdgToParticleHypothesis;
+
+    /** Validation section */
+    bool                          m_validationMode;
+    ToolHandle<IPhysicsValidationTool>  m_validationTool;
+
+    ServiceHandle<ISF::IParticleBroker>              m_particleBroker;
+    ServiceHandle<ISF::ITruthSvc>                    m_truthRecordSvc;
+
+    /** useful for the angle calculation of the brem photon */ 
+    double                                           m_oneOverThree;
+
+    /** cache incoming particle */
+    mutable const ISF::ISFParticle*                  m_isp;
+    
+    /** cache layer properties */
+    mutable const Trk::Layer*                       m_layer;
+    mutable const Trk::MaterialProperties*          m_matProp;           
+    mutable float                                   m_thicknessInX0;
+    mutable float                                   m_thicknessInL0;
+     
+	double                                          m_projectionFactor;
+  };
+        
 }
 
+//!< define the templated function   
+#include "McMaterialEffectsEngine.icc" 
+
 #endif // ISF_FATRASTOOLS_MCMATERIALEFFECTENIGINE_H
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.icc b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.icc
new file mode 100644
index 0000000000000000000000000000000000000000..2eea3be465e631fb54bede7f43334aabbd33723e
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsEngine.icc
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// McMaterialEffectsEngine.icc, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+	
+#include "TrkExInterfaces/IMaterialEffectsEngine.h"
+#include "ISF_Event/ParticleClipboard.h"
+#include "TrkGeometry/Layer.h"
+#include <iostream>
+
+template <class T> Trk::ExtrapolationCode iFatras::McMaterialEffectsEngine::handleMaterialT( Trk::ExtrapolationCell<T>& eCell,
+	 	   			  						     Trk::PropDirection dir,
+											     Trk::MaterialUpdateStage matupstage) const 
+{
+  // get parent particle
+  const ISF::ISFParticle *isp = ISF::ParticleClipboard::getInstance().getParticle();
+  // something is seriously wrong if there is no parent particle
+  assert(isp);
+  m_isp = isp;
+
+  // the Extrapolator made sure that the layer is the lead layer && the parameters are the lead parameters
+  m_layer = eCell.leadLayer;
+  if (m_layer && eCell.leadParameters) {
+     // path correction		     
+     double pathCorrection = m_layer->surfaceRepresentation().pathCorrection(eCell.leadParameters->position(),dir*(eCell.leadParameters->momentum()));
+     // the relative direction wrt with the layer
+     Trk::PropDirection rlDir = (pathCorrection > 0. ? Trk::alongMomentum : Trk::oppositeMomentum);
+     // multiply by the pre-and post-update factor
+     double mFactor = m_layer->layerMaterialProperties()->factor(rlDir, matupstage);
+     //EX_MSG_DEBUG(eCell.navigationStep, "Update", "char", "Update on layer with index " << m_layer->layerIndex().value() << " - corr factor = " << pathCorrection*mFactor); 
+
+     const Trk::MaterialProperties* materialProperties = m_layer->layerMaterialProperties()->fullMaterial(eCell.leadParameters->position());
+     if ( materialProperties ) {
+       m_matProp = materialProperties;
+       m_thicknessInX0 = mFactor*m_matProp->thicknessInX0();
+       m_thicknessInL0 = mFactor*m_matProp->thicknessInL0();
+
+       float mFraction=0.;   
+       return processMaterialOnLayer(isp,eCell,dir,mFraction);
+     }
+  }
+  return Trk::ExtrapolationCode::InProgress;
+}
+
+
+
+
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsUpdator.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsUpdator.h
index aa89a366e20e8a506e284e2c88d71ea2166daba9..0e3ac799713abeee0bd45e21744239c5507e5a9f 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsUpdator.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/McMaterialEffectsUpdator.h
@@ -61,7 +61,7 @@ namespace iFatras {
   class IPhysicsValidationTool;
   class IHadronicInteractionProcessor;
   class IPhotonConversionTool; 
-  class IParticleDecayer;
+  class IParticleDecayHelper;
       
   /** @class McMaterialEffectsUpdator
   
@@ -217,7 +217,7 @@ namespace iFatras {
      ToolHandle<IHadronicInteractionProcessor>    m_hadIntProcessor;
      
      /** Particle Decay */
-     ToolHandle<IParticleDecayer>                 m_particleDecayer;
+     ToolHandle<IParticleDecayHelper>                 m_particleDecayer;
      
      /** Minimum momentum cut */
      double                                       m_minimumMomentum;
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerGaussianMixture.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerGaussianMixture.h
new file mode 100644
index 0000000000000000000000000000000000000000..a7032a4953d03164a3372bc51887f6b936c24614
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerGaussianMixture.h
@@ -0,0 +1,105 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// MultipleScatteringSamplerGaussianMixture.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERGAUSSIANMIXTURE_H
+#define ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERGAUSSIANMIXTURE_H
+ 
+// Gaudi
+#include "AthenaBaseComps/AthAlgTool.h"
+// Trk
+#include "ISF_FatrasInterfaces/IMultipleScatteringSampler.h"
+#include "TrkEventPrimitives/PropDirection.h"
+#include "TrkEventPrimitives/ParticleHypothesis.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "AthenaKernel/IAtRndmGenSvc.h"
+
+#include "CLHEP/Random/RandFlat.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "EventPrimitives/EventPrimitives.h"
+
+namespace Trk {
+  class MaterialProperties;
+}
+
+namespace iFatras {
+  
+  /**@class MultipleScatteringSamplerGaussianMixture
+     
+     @author Noemi.Calace@cern.ch , Andreas.Salzburger@cern.ch
+  */
+  
+  class MultipleScatteringSamplerGaussianMixture : public AthAlgTool,
+    virtual public IMultipleScatteringSampler {
+      
+  public:
+      /** AlgTool like constructor */
+      MultipleScatteringSamplerGaussianMixture(const std::string&,const std::string&,const IInterface*);
+      
+      /**Virtual destructor*/
+      virtual ~MultipleScatteringSamplerGaussianMixture();
+      
+      /** AlgTool initailize method.*/
+      StatusCode initialize();
+      
+      /** AlgTool finalize method */
+      StatusCode finalize();
+      
+      /** Calculate the sigma on theta introduced by multiple scattering,
+	  according to the RutherFord-Scott Formula           
+      */
+      double simTheta(const Trk::MaterialProperties& mat,
+		      double p,
+		      double pathcorrection,
+		      Trk::ParticleHypothesis particle=Trk::pion,
+		      double deltaE=0.) const;
+      
+  private:
+      bool                  m_log_include;           //!< boolean switch to include log term  
+      
+      bool                  m_optGaussianMixtureG4;  //!< modifies the Fruehwirth/Regler model to fit with G4
+      
+      //========== used for Gaussian mixture model =================================================
+      
+      /** Random Generator service  */
+      ServiceHandle<IAtRndmGenSvc>                 m_rndGenSvc;
+      /** Random engine  */
+      CLHEP::HepRandomEngine*                      m_randomEngine;
+      std::string                                  m_randomEngineName;                   //!< Name of the random number stream
+       
+      static Trk::ParticleMasses s_particleMasses;        //!< struct of Particle masses
+      
+      static double         s_main_RutherfordScott;  //!< main factor of Rutherford-Scott formula
+      static double         s_log_RutherfordScott;   //!< log factor of Rutherford-Scott formula
+       
+      static double         s_main_RossiGreisen;     //!< main factor for Rossi-Greisen formula
+      static double         s_log_RossiGreisen;      //!< main factor for Rossi-Greisen formula
+      
+      
+      // ========= Gaussian mixture model Fruehwirth, Regler Nucl. Inst. Methods A 456(2001) =========
+      static double         s_gausMixSigma1_a0;     //!< Gaussian mixture model: Sigma parameter a0
+      static double         s_gausMixSigma1_a1;     //!< Gaussian mixture model: Sigma parameter a1
+      static double         s_gausMixSigma1_a2;     //!< Gaussian mixture model: Sigma parameter a2
+      
+      static double         s_gausMixEpsilon_a0;     //!< Gaussian mixture model: Epsilon parameter a0
+      static double         s_gausMixEpsilon_a1;     //!< Gaussian mixture model: Epsilon parameter a1
+      static double         s_gausMixEpsilon_a2;     //!< Gaussian mixture model: Epsilon parameter a2
+      
+      static double         s_gausMixEpsilon_b0;     //!< Gaussian mixture model: Epsilon parameter b0
+      static double         s_gausMixEpsilon_b1;     //!< Gaussian mixture model: Epsilon parameter b1
+      static double         s_gausMixEpsilon_b2;     //!< Gaussian mixture model: Epsilon parameter b2
+       
+      static double 	    s_projectionFactor;	     //!< projection factor to scale the projected angle out of the plane
+      
+    };
+  
+  
+} // end of namespace
+
+
+#endif // ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERGAUSSIANMIXTURE_H
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerGeneralMixture.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerGeneralMixture.h
new file mode 100644
index 0000000000000000000000000000000000000000..113ee363c12e9e18634fc3ebce6cfc51b0ca6c78
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerGeneralMixture.h
@@ -0,0 +1,99 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// MultipleScatteringSamplerGeneralMixture.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERGENERALMIXTURE_H
+#define ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERGENERALMIXTURE_H
+ 
+// Gaudi
+#include "AthenaBaseComps/AthAlgTool.h"
+// Trk
+#include "ISF_FatrasInterfaces/IMultipleScatteringSampler.h"
+#include "TrkEventPrimitives/PropDirection.h"
+#include "TrkEventPrimitives/ParticleHypothesis.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "AthenaKernel/IAtRndmGenSvc.h"
+
+#include "CLHEP/Random/RandFlat.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "EventPrimitives/EventPrimitives.h"
+
+namespace Trk {
+  class MaterialProperties;
+}
+
+namespace iFatras {
+  
+  /**@class MultipleScatteringSamplerGeneralMixture
+     
+     @author Noemi.Calace@cern.ch , Andreas.Salzburger@cern.ch, Artem.Basalaev@cern.ch
+  */
+  
+  class MultipleScatteringSamplerGeneralMixture : public AthAlgTool,
+    virtual public IMultipleScatteringSampler {
+      
+  public:
+      /** AlgTool like constructor */
+      MultipleScatteringSamplerGeneralMixture(const std::string&,const std::string&,const IInterface*);
+      
+      /**Virtual destructor*/
+      virtual ~MultipleScatteringSamplerGeneralMixture();
+      
+      /** AlgTool initailize method.*/
+      StatusCode initialize();
+      
+      /** AlgTool finalize method */
+      StatusCode finalize();
+      
+      /** Calculate theta introduced by multiple scattering,
+	  according to the RutherFord-Scott Formula           
+      */
+      double simTheta(const Trk::MaterialProperties& mat,
+			 double p,
+			 double pathcorrection,
+			 Trk::ParticleHypothesis particle=Trk::pion,
+			 double deltaE=0.) const;
+      
+  private:
+      bool                  m_log_include;           //!< boolean switch to include log term  
+      static double 	    s_projectionFactor;	     //!< projection factor to scale the projected angle out of the plane
+      
+      //========== used for General mixture model =================================================
+      
+      /** Random Generator service  */
+      ServiceHandle<IAtRndmGenSvc>                 m_rndGenSvc;
+      /** Random engine  */
+      CLHEP::HepRandomEngine*                      m_randomEngine;
+      std::string                                  m_randomEngineName;                   //!< Name of the random number stream
+       
+      static Trk::ParticleMasses s_particleMasses;        //!< struct of Particle masses
+       
+      static double         s_main_RossiGreisen;     //!< main factor for Rossi-Greisen formula
+      static double         s_log_RossiGreisen;      //!< main factor for Rossi-Greisen formula
+      
+      
+      // ========= General mixture model R.Frühwirth, M. Liendl. Comp. Phys. Comm. 141 (2001) 230–246 =========
+      static double	    s_genMixScale;	    //!< General mixture model: Scaling factor
+      
+      //!< General mixture model: get parameters for single gaussian simulation
+      double 	*getGaussian(double beta, double p,double dOverX0, double scale) const;
+      //!< General mixture model: get parameters for gaussian mixture
+      double 	*getGaussmix(double beta, double p,double dOverX0,double Z, double scale) const;
+      //!< General mixture model: get parameters for semi-gaussian mixture
+      double 	*getSemigauss(double beta,double p,double dOverX0,double Z, double scale) const;
+      //!< General mixture model: simulate semi-gaussian mixture
+      double 	simGaussmix(double * scattering_params) const;
+      //!< General mixture model: simulate gaussian mixture
+      double 	simSemigauss(double * scattering_params) const;
+    };
+  
+  
+} // end of namespace
+
+
+#endif // ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERGENERALMIXTURE_H
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerHighland.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerHighland.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ede9ea15b95700ef1b135e3285bcea28999a912
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/MultipleScatteringSamplerHighland.h
@@ -0,0 +1,95 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// MultipleScatteringSamplerHighland.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERHIGHLAND_H
+#define ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERHIGHLAND_H
+ 
+// Gaudi
+#include "AthenaBaseComps/AthAlgTool.h"
+// Trk
+#include "ISF_FatrasInterfaces/IMultipleScatteringSampler.h"
+#include "TrkEventPrimitives/PropDirection.h"
+#include "TrkEventPrimitives/ParticleHypothesis.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "AthenaKernel/IAtRndmGenSvc.h"
+
+#include "CLHEP/Random/RandFlat.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "EventPrimitives/EventPrimitives.h"
+
+namespace Trk {
+  class MaterialProperties;
+}
+
+namespace iFatras {
+  
+  /**@class MultipleScatteringSamplerHighland
+     
+     The Formula used is the highland formula for the projected scattering angle :
+     
+     @f$ \theta_{ms} = \frac{13.6MeV}{p}\cdot\sqrt{t/X_{0}}[1 + 0.038\ln(t/X_{0})] @f$
+     
+     What is returned is the square of the expectation value of the deflection 
+     @f$ < (\theta_ms)^2 > = \sigma_ms^2 @f$
+     
+     @author Noemi.Calace@cern.ch , Andreas.Salzburger@cern.ch
+  */
+  
+  class MultipleScatteringSamplerHighland : public AthAlgTool,
+    virtual public IMultipleScatteringSampler {
+      
+  public:
+      /** AlgTool like constructor */
+      MultipleScatteringSamplerHighland(const std::string&,const std::string&,const IInterface*);
+      
+      /**Virtual destructor*/
+      virtual ~MultipleScatteringSamplerHighland();
+      
+      /** AlgTool initailize method.*/
+      StatusCode initialize();
+      
+      /** AlgTool finalize method */
+      StatusCode finalize();
+      
+      /** Calculate the theta introduced by multiple scattering,
+	  according to the RutherFord-Scott Formula           
+      */
+      double simTheta(const Trk::MaterialProperties& mat,
+		      double p,
+		      double pathcorrection,
+		      Trk::ParticleHypothesis particle=Trk::pion,
+		      double deltaE=0.) const;
+      
+  private:
+      bool                  m_log_include;           //!< boolean switch to include log term  
+           
+      /** Random Generator service  */
+      ServiceHandle<IAtRndmGenSvc>                 m_rndGenSvc;
+      /** Random engine  */
+      CLHEP::HepRandomEngine*                      m_randomEngine;
+      std::string                                  m_randomEngineName;                   //!< Name of the random number stream
+
+      static Trk::ParticleMasses s_particleMasses;        //!< struct of Particle masses
+      
+      static double         s_main_RutherfordScott;  //!< main factor of Rutherford-Scott formula
+      static double         s_log_RutherfordScott;   //!< log factor of Rutherford-Scott formula
+       
+      static double         s_main_RossiGreisen;     //!< main factor for Rossi-Greisen formula
+      static double         s_log_RossiGreisen;      //!< main factor for Rossi-Greisen formula
+      
+      static double 	    s_projectionFactor;	     //!< projection factor to scale the projected angle out of the plane
+
+      
+    };
+  
+  
+} // end of namespace
+
+
+#endif // ISF_FATRASTOOLS_MULTIPLESCATTERINGSAMPLERHIGHLAND_H
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhotonConversionTool.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhotonConversionTool.h
index a7807c02065eb4e0001a9684b7d1036db296f21a..88ce25922621200c699147e0003fdf80c5070628 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhotonConversionTool.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhotonConversionTool.h
@@ -17,7 +17,6 @@
 // Trk
 #include "TrkEventPrimitives/PropDirection.h"
 #include "TrkEventPrimitives/ParticleHypothesis.h"
-#include "TrkParameters/TrackParameters.h"
 #include "TrkExUtils/MaterialUpdateMode.h"
 #include "TrkDetDescrUtils/GeometrySignature.h" 
 // ISF
@@ -75,12 +74,12 @@ namespace iFatras {
 			  double p) const;
       
       /** interface for processing of the presampled pair production */
-      bool doConversion(double time, const Trk::TrackParameters& parm,
+      bool doConversion(double time, const Trk::NeutralParameters& parm,
 			const Trk::ExtendedMaterialProperties* extMatProp=0) const;
       
       /** interface for processing of the presampled nuclear interactions on layer*/
       ISF::ISFParticleVector doConversionOnLayer(const ISF::ISFParticle* parent, 
-						 double time, const Trk::TrackParameters& parm,
+						 double time, const Trk::NeutralParameters& parm,
 						 const Trk::ExtendedMaterialProperties *ematprop=0) const;
 
 
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhysicsValidationTool.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhysicsValidationTool.h
index b3d1194bb6cae414a79520eaee73a61f119e2af0..032616b056b541c31ef790655555d7db8b66be08 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhysicsValidationTool.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/PhysicsValidationTool.h
@@ -67,9 +67,18 @@ namespace iFatras
     /** AlgTool finalize method */
 
     virtual StatusCode finalize();
-    
-    /** Fill ntuple */
+
+    /** ISFParticle info: old transport tool */
     void saveISFParticleInfo(const ISF::ISFParticle& isp, int endProcess, const Trk::TrackParameters* ePar, double time, double dX0 );
+    
+    /** ISFParticle info: new transport tool */
+    void saveISFParticleInfo(const ISF::ISFParticle& isp, const Trk::ExtrapolationCell<Trk::TrackParameters>& ec,
+				     Trk::ExtrapolationCode ecode );
+
+    /** ISFParticle info: new transport tool */
+    void saveISFParticleInfo(const ISF::ISFParticle& isp, const Trk::ExtrapolationCell<Trk::NeutralParameters>& ec,
+				     Trk::ExtrapolationCode ecode );
+
 
     void saveISFVertexInfo(int process,Amg::Vector3D vertex,const ISF::ISFParticle& isp,Amg::Vector3D primIn,
 			   Amg::Vector3D* primOut, const ISF::ISFParticleVector children);
@@ -85,6 +94,8 @@ namespace iFatras
               ATH_MSG_DEBUG("[ fatras setup ] Successfully retrieved " << thandle);
               return StatusCode::SUCCESS;
      }
+     
+     void saveInfo(const ISF::ISFParticle& isp); 
       
     /*---------------------------------------------------------------------
      *  Private members
@@ -105,6 +116,10 @@ namespace iFatras
     mutable float                                                         m_pph;
     mutable float                                                         m_p;
     mutable float                                                         m_eloss;
+    mutable float                                                         m_ionloss;
+    mutable float                                                         m_radloss;
+    mutable float                                                         m_zOaTr;
+    mutable float                                                         m_wZ;
     mutable float                                                         m_thIn;
     mutable float                                                         m_phIn;
     mutable float                                                         m_dIn;
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/ProcessSamplingTool.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/ProcessSamplingTool.h
index 30c003917dab69d7dea10d6a7a60d160a2ae462e..a0210c6b2343d9870bcc0240f5b3d9357c09a0a7 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/ProcessSamplingTool.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/ProcessSamplingTool.h
@@ -23,8 +23,16 @@
 #include "TrkParameters/TrackParameters.h"
 #include "TrkEventPrimitives/ParticleHypothesis.h"
 
+namespace ISF {
+  class ITruthSvc;
+}
+
 namespace iFatras 
 {
+  class IHadronicInteractionProcessor;
+  class IPhotonConversionTool; 
+  class IParticleDecayHelper;
+  class IPhysicsValidationTool;
     
   /** @class ProcessSamplingTool 
       
@@ -51,8 +59,15 @@ namespace iFatras
     virtual StatusCode finalize();
 
     /** Process pre-sampling : to be moved into material updators eventually */
-    Trk::PathLimit sampleProcess(double mom, double charge, Trk::ParticleHypothesis pHypothesis);
+    Trk::PathLimit sampleProcess(double mom, double charge, Trk::ParticleHypothesis pHypothesis) const;
     
+    /** Process simulation */
+    ISF::ISFParticleVector  interact(const ISF::ISFParticle* parent,
+				     Trk::ExCellCharged& eCell,
+				     const Trk::Material* mat) const;
+    ISF::ISFParticleVector  interact(const ISF::ISFParticle* parent,
+				     Trk::ExCellNeutral& eCell,
+				     const Trk::Material* mat) const;
   private:
      /** templated Tool retrieval - gives unique handling & look and feel */
      template <class T> StatusCode retrieveTool(ToolHandle<T>& thandle){
@@ -72,8 +87,25 @@ namespace iFatras
      ServiceHandle<IAtRndmGenSvc>                 m_rndGenSvc;
      CLHEP::HepRandomEngine*                      m_randomEngine;
      std::string                                  m_randomEngineName;         //!< Name of the random number stream
+     
+     /** Truth record */
+     ServiceHandle<ISF::ITruthSvc>                m_truthRecordSvc;
+
+     /** hadronic interaction */
+     bool                                         m_hadInt;
+     ToolHandle<IHadronicInteractionProcessor>    m_hadIntProcessor;
+     
+     /** decay */
+     ToolHandle<IParticleDecayHelper>                 m_particleDecayer;
+
+      /** IPhotonConversionTool */
+     ToolHandle<iFatras::IPhotonConversionTool>   m_conversionTool;
+
+     Trk::ParticleMasses                          m_particleMasses;    //!< Struct of Particle masses
 
-     Trk::ParticleMasses                 m_particleMasses;    //!< Struct of Particle masses
+     /** validation */
+     bool                                         m_validationMode;
+     ToolHandle<IPhysicsValidationTool>           m_validationTool;
 
   }; 
 }
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportEngine.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportEngine.h
index 583fbc635b1fe3c194d1406025f9d0a2dcdb5b7f..8ae9d784196e70049d821d151e00462653781757 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportEngine.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportEngine.h
@@ -16,12 +16,13 @@
 #include "AthenaKernel/IAtRndmGenSvc.h"
 #include "TrkExInterfaces/IExtrapolationEngine.h"
 #include "TrkExUtils/ExtrapolationCell.h"
-// iFatras
-#include "ISF_FatrasInterfaces/ITransportTool.h"
+// ISF
+#include "ISF_Interfaces/IParticleProcessor.h"
 
 // Tracking
 #include "TrkEventPrimitives/PdgToParticleHypothesis.h"
 #include "TrkEventPrimitives/ParticleHypothesis.h"
+#include "TrkDetDescrUtils/GeometrySignature.h"
 
 class IIncidentSvc;
 
@@ -39,6 +40,7 @@ namespace iFatras
   class ISimHitCreator;    
   class IParticleDecayHelper;
   class IProcessSamplingTool;
+  class IPhysicsValidationTool;
    
   /** @class TransportEngine 
       
@@ -48,7 +50,7 @@ namespace iFatras
       @author Noemi Calace -at- cern.ch, Andreas Salzburger -at cern.ch 
   */  
   
-  class TransportEngine : virtual public ITransportTool,
+  class TransportEngine : virtual public ISF::IParticleProcessor,
     public AthAlgTool
     {
     public:
@@ -74,8 +76,8 @@ namespace iFatras
                                                   Trk::ExtrapolationCode eCode,
                                                   const Amg::Vector3D& position,
                                                   const Amg::Vector3D& momentum,
-                                                  double charge,
-                                                  double stime);
+						  double stime,
+						  Trk::GeometrySignature geoID);
       
       /** templated Tool retrieval - gives unique handling & look and feel */
       template <class T> StatusCode retrieveTool(ToolHandle<T>& thandle)
@@ -122,6 +124,9 @@ namespace iFatras
                                                 
       Trk::PdgToParticleHypothesis                 m_pdgToParticleHypothesis;
       Trk::ParticleMasses                          m_particleMasses;      //!< Struct of Particle masses
+
+      bool                                         m_validationMode;
+      ToolHandle<IPhysicsValidationTool>           m_validationTool;
                                                                                                 
     }; 
     
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportTool.h b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportTool.h
index cb5eb58f8158c323cbb4f6d7b55584e78cf320ff..08debd043beefe45892c13edb3d60dd2a9eaf58d 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportTool.h
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/ISF_FatrasTools/TransportTool.h
@@ -16,8 +16,8 @@
 #include "AthenaKernel/IAtRndmGenSvc.h"
 #include "TrkExInterfaces/ITimedExtrapolator.h"
 
-// iFatras
-#include "ISF_FatrasInterfaces/ITransportTool.h"
+// IFS
+#include "ISF_Interfaces/IParticleProcessor.h"
 
 // Tracking
 #include "TrkEventPrimitives/PdgToParticleHypothesis.h"
@@ -53,7 +53,7 @@ namespace iFatras
       @author Andreas.Salzburger -at- cern.ch
   */  
   
-  class TransportTool : virtual public ITransportTool,
+  class TransportTool : virtual public ISF::IParticleProcessor,
                         public AthAlgTool
   {
   public:
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/cmt/requirements b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/cmt/requirements
index 6454dd51256d41c9da3c5c1ae4cea0299739d0a9..81bf736a0b4899bc45b165820f2b320d7dbe5328 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/cmt/requirements
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/cmt/requirements
@@ -7,46 +7,50 @@ manager Wolfgang Lukas <Wolfgang.Lukas@cern.ch>
 public
 ########## Control #############################################################
 use AtlasPolicy              AtlasPolicy-*
-use AthenaBaseComps          AthenaBaseComps-*          Control
-use AthenaKernel             AthenaKernel-*             Control
-use GaudiInterface           GaudiInterface-*           External
+use AthenaBaseComps          AthenaBaseComps-*         Control
+use AthenaKernel             AthenaKernel-*            Control
+use GaudiInterface           GaudiInterface-*          External
 
-########## ISF #################################################################
-use ISF_Event                ISF_Event-*                Simulation/ISF/ISF_Core
-use ISF_FatrasInterfaces     ISF_FatrasInterfaces-*     Simulation/ISF/ISF_Fatras
+########## External ############################################################
+use AtlasCLHEP               AtlasCLHEP-*              External
 
+########## ISF #################################################################
+use ISF_Event                ISF_Event-*               Simulation/ISF/ISF_Core
+use ISF_FatrasInterfaces     ISF_FatrasInterfaces-*    Simulation/ISF/ISF_Fatras
+use ISF_Interfaces           ISF_Interfaces-*          Simulation/ISF/ISF_Core 
+ 
 ########## Barcode #############################################################
-use BarcodeInterfaces        BarcodeInterfaces-*        Simulation/Barcode
+use BarcodeInterfaces        BarcodeInterfaces-*       Simulation/Barcode
 
 ########## Tracking ############################################################
-use TrkDetDescrUtils         TrkDetDescrUtils-*         Tracking/TrkDetDescr
-use TrkEventPrimitives       TrkEventPrimitives-*       Tracking/TrkEvent
-use TrkExInterfaces          TrkExInterfaces-*          Tracking/TrkExtrapolation
-use TrkExUtils               TrkExUtils-*               Tracking/TrkExtrapolation
-use TrkParameters            TrkParameters-*            Tracking/TrkEvent
+use TrkDetDescrUtils         TrkDetDescrUtils-*        Tracking/TrkDetDescr
+use TrkEventPrimitives       TrkEventPrimitives-*      Tracking/TrkEvent
+use TrkExInterfaces          TrkExInterfaces-*         Tracking/TrkExtrapolation
+use TrkExUtils               TrkExUtils-*              Tracking/TrkExtrapolation
+use TrkParameters            TrkParameters-*           Tracking/TrkEvent
+use EventPrimitives          EventPrimitives-*         Event
+use GeoPrimitives            GeoPrimitives-*           DetectorDescription
+use TrkGeometry              TrkGeometry-*             Tracking/TrkDetDescr
+
 
 private
 ########## Control #############################################################
 use StoreGate                StoreGate-*                Control
 
 ########## External ############################################################
-use AtlasCLHEP               AtlasCLHEP-*               External
 use AtlasROOT                AtlasROOT-*                External
 
 ########## RandomNumbers #######################################################
 use AtlasCLHEP_RandomGenerators AtlasCLHEP_RandomGenerators-* Simulation/Tools
 
 ########## Tracking ############################################################
-use TrkGeometry              TrkGeometry-*              Tracking/TrkDetDescr
-use TrkSurfaces              TrkSurfaces-*              Tracking/TrkDetDescr
-use TrkVolumes               TrkVolumes-*               Tracking/TrkDetDescr
-use TrkDetDescrInterfaces    TrkDetDescrInterfaces-*    Tracking/TrkDetDescr
-use TrkTrack                 TrkTrack-*                 Tracking/TrkEvent
-use TrkMaterialOnTrack       TrkMaterialOnTrack-*       Tracking/TrkEvent
-use TrkNeutralParameters     TrkNeutralParameters-*     Tracking/TrkEvent
-
-########## ISF #################################################################
-use ISF_Interfaces           ISF_Interfaces-*           Simulation/ISF/ISF_Core   
+use TrkVolumes               TrkVolumes-*              Tracking/TrkDetDescr
+use TrkDetDescrInterfaces    TrkDetDescrInterfaces-*   Tracking/TrkDetDescr
+use TrkTrack                 TrkTrack-*                Tracking/TrkEvent
+use TrkMaterialOnTrack       TrkMaterialOnTrack-*      Tracking/TrkEvent
+use TrkNeutralParameters     TrkNeutralParameters-*    Tracking/TrkEvent
+use TrkSurfaces              TrkSurfaces-*             Tracking/TrkDetDescr
+use TrkExEngine              TrkExEngine-*             Tracking/TrkExtrapolation
 
 ########## ISF #################################################################
 
@@ -67,6 +71,6 @@ library ISF_FatrasTools *.cxx components/*.cxx
 apply_pattern component_library
 
 # use the following to compile with debug information
-#private
+private
 #macro cppdebugflags '$(cppdebugflags_s)'
 #macro_remove componentshr_linkopts "-Wl,-s"
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/HadIntProcessorParametric.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/HadIntProcessorParametric.cxx
index efae1ce5241196fa1515e5148b9c9348674d11a0..7bcdb02f57b89f85d87dc5606f92d3d3a1cb0277 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/HadIntProcessorParametric.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/HadIntProcessorParametric.cxx
@@ -199,9 +199,10 @@ StatusCode iFatras::HadIntProcessorParametric::finalize()
 }
 
 
-bool iFatras::HadIntProcessorParametric::hadronicInteraction(const Trk::TrackParameters& parm, double p, double /*E*/,
-                         const Trk::MaterialProperties& mprop, double pathCorrection,
-                         Trk::ParticleHypothesis particle) const 
+bool iFatras::HadIntProcessorParametric::hadronicInteraction(const Amg::Vector3D& position, const Amg::Vector3D& momentum, 
+							     double p, double /*E*/, double charge, 
+							     const Trk::MaterialProperties& mprop, double pathCorrection,
+							     Trk::ParticleHypothesis particle) const 
 {
   const Trk::MaterialProperties* extMprop = dynamic_cast<const Trk::MaterialProperties*>(&mprop);
   double prob = 0.;
@@ -209,7 +210,7 @@ bool iFatras::HadIntProcessorParametric::hadronicInteraction(const Trk::TrackPar
   // m_hadIntProbScale is used later, not here
   if (extMprop && !m_hadIntFromX0) {
 
-    double al = absorptionLength(extMprop, p, parm.charge(), particle);  // in mm
+    double al = absorptionLength(extMprop, p, charge, particle);  // in mm
 
     if (al>0.) prob = exp( (-1.)*pathCorrection*extMprop->thickness()/al );
     else       prob = exp( (-1.)*pathCorrection*extMprop->thicknessInL0()); 
@@ -228,8 +229,8 @@ bool iFatras::HadIntProcessorParametric::hadronicInteraction(const Trk::TrackPar
   // (1. - prob) is generally O(0.01), so this is the right way to scale it
   // TODO fix time info (if needed)
   if (CLHEP::RandFlat::shoot(m_randomEngine) < (1. - prob) * m_hadIntProbScale ) return recordHadState(0.,p, 
-												       parm.position(),
-												       parm.momentum().unit(),
+												       position,
+												       momentum.unit(),
 												       particle);
   
   // no hadronic interactions were computed
@@ -239,7 +240,7 @@ bool iFatras::HadIntProcessorParametric::hadronicInteraction(const Trk::TrackPar
 
 /** absorption length */
 double iFatras::HadIntProcessorParametric::absorptionLength(const Trk::MaterialProperties* mat,
-						   double p, double, Trk::ParticleHypothesis particle) const {
+							    double p, double, Trk::ParticleHypothesis particle) const {
   double al = mat->l0();
 
   /* // these parametrization comes from comparison with G4 sampler, but give too many interactions 
@@ -676,7 +677,7 @@ ISF::ISFParticleVector iFatras::HadIntProcessorParametric::getHadState(const ISF
 
 } 
 
-bool iFatras::HadIntProcessorParametric::doHadronicInteraction(double time,const Trk::TrackParameters& parm,
+bool iFatras::HadIntProcessorParametric::doHadronicInteraction(double time, const Amg::Vector3D& position, const Amg::Vector3D& momentum, 
 							       const Trk::Material* /*ematprop*/,
 							       Trk::ParticleHypothesis particle, bool processSecondaries) const {
   // get parent particle
@@ -684,7 +685,7 @@ bool iFatras::HadIntProcessorParametric::doHadronicInteraction(double time,const
   // something is seriously wrong if there is no parent particle
   assert(parent);
 
-  ISF::ISFParticleVector ispVec=getHadState(parent,time, parm.momentum().mag(), parm.position(), parm.momentum().unit(),particle);
+  ISF::ISFParticleVector ispVec=getHadState(parent, time, momentum.mag(), position, momentum.unit(), particle);
 
   // having no secondaries does not necessarily mean the interaction did not take place  : TODO : add flag into ::getHadState
   //  if (!ispVec.size()) return false;
@@ -699,12 +700,13 @@ bool iFatras::HadIntProcessorParametric::doHadronicInteraction(double time,const
 
 }
 
-ISF::ISFParticleVector iFatras::HadIntProcessorParametric::doHadIntOnLayer(const ISF::ISFParticle* parent, double time,const Trk::TrackParameters& parm,
-							       const Trk::MaterialProperties* /*ematprop*/,
-							       Trk::ParticleHypothesis particle) const {
-
-  return getHadState(parent, time, parm.momentum().mag(), parm.position(), parm.momentum().unit(),particle);
+ISF::ISFParticleVector iFatras::HadIntProcessorParametric::doHadIntOnLayer(const ISF::ISFParticle* parent, double time,
+									   const Amg::Vector3D& position, const Amg::Vector3D& momentum,
+									   const Trk::Material* /*emat*/,
+									   Trk::ParticleHypothesis particle) const {
 
+  return getHadState(parent, time, momentum.mag(), position, momentum.unit(), particle);
+  
 }
 
 /** interface for processing of the presampled nuclear interaction */                           
@@ -716,17 +718,17 @@ bool iFatras::HadIntProcessorParametric::recordHadState(double time, double p,
   const ISF::ISFParticle *parent = ISF::ParticleClipboard::getInstance().getParticle();
   // something is seriously wrong if there is no parent particle
   assert(parent);
-
-  ISF::ISFParticleVector ispVec=getHadState(parent,time, p, vertex, particleDir, particle);
-
+  
+  ISF::ISFParticleVector ispVec=getHadState(parent, time, p, vertex, particleDir, particle);
+  
   // having no secondaries does not necessarily mean the interaction did not take place : TODO : add flag into ::getHadState
   //  if (!ispVec.size()) return false;
-
+  
   // push onto ParticleStack
   if (ispVec.size() ) {
     for (unsigned int ic=0; ic<ispVec.size(); ic++) m_particleBroker->push(ispVec[ic], parent);
   }
-
+  
   return true;
 }
 
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McBetheHeitlerEnergyLossUpdator.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McBetheHeitlerEnergyLossUpdator.cxx
deleted file mode 100755
index 8eac108424c4aaa0e2b57bd1eb755e581d8498d0..0000000000000000000000000000000000000000
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McBetheHeitlerEnergyLossUpdator.cxx
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/***************************************************************************************
-			McBetheHeitlerEnergyLossUpdator.cxx -  description
-			---------------------------------------------------
-begin                : Wednesday 28th June 2006
-author               : atkinson
-email                : Tom.Atkinson@cern.ch
-decription           : Implementation code for McBetheHeitlerEnergyLossUpdator class
-***************************************************************************************/
-
-// class header include
-#include "ISF_FatrasTools/McBetheHeitlerEnergyLossUpdator.h"
-
-#include "TrkGeometry/MaterialProperties.h"
-#include "TrkMaterialOnTrack/EnergyLoss.h"
-#include "CLHEP/Random/RandGamma.h"
-#include <cmath>
-
-
-// static partilce masses
-Trk::ParticleMasses iFatras::McBetheHeitlerEnergyLossUpdator::s_particleMasses;
-
-iFatras::McBetheHeitlerEnergyLossUpdator::McBetheHeitlerEnergyLossUpdator( const std::string& type, const std::string& name, const IInterface* parent )
-  :
-  AthAlgTool( type, name, parent ),
-  m_rndmGenSvc("AtDSFMTGenSvc", name),
-  m_randomEngine(0),
-  m_randomEngineName("FatrasRnd"),
-  m_cashedPathLength(0.),
-  m_numberPointsInPDF(100000),
-  m_scaleFactor(1.0)
-{
-  
-  declareInterface<IEnergyLossUpdator>(this);
-  // get the property from outside
-  declareProperty("ScaleFactor",      m_scaleFactor);
-  declareProperty("RandomNumberService"                 , m_rndmGenSvc         , "Random number generator");
-  declareProperty("RandomStreamName"                    , m_randomEngineName   , "Name of the random number stream");
-	
-}
-
-iFatras::McBetheHeitlerEnergyLossUpdator::~McBetheHeitlerEnergyLossUpdator(){}
-
-StatusCode iFatras::McBetheHeitlerEnergyLossUpdator::initialize()
-{
-
-  ATH_MSG_INFO( "initialize()" );
-    
-  if ( m_rndmGenSvc.retrieve().isFailure() ){
-    ATH_MSG_FATAL( "Could not retrieve " << m_rndmGenSvc );
-    return StatusCode::FAILURE;
-  }
-  //Get own engine with own seeds:
-  m_randomEngine = m_rndmGenSvc->GetEngine(m_randomEngineName);
-  if (!m_randomEngine) {
-      ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
-      return StatusCode::FAILURE;
-  }
-  return StatusCode::SUCCESS;  
-}
-
-StatusCode iFatras::McBetheHeitlerEnergyLossUpdator::finalize()
-{
-  
-  ATH_MSG_INFO( "finalize() successful" );
-  return StatusCode::SUCCESS;	
-}
-
-Trk::EnergyLoss* iFatras::McBetheHeitlerEnergyLossUpdator::energyLoss(
-                    const Trk::MaterialProperties& materialProperties,
-                    double pInitial,
-                    double pathCorrection,
-                    Trk::PropDirection direction,
-                    Trk::ParticleHypothesis,
-                    bool) const
-{
-  
-  double pathLength = pathCorrection * materialProperties.thickness() / materialProperties.x0();
-  
-  double u = CLHEP::RandGamma::shoot(m_randomEngine, pathLength / log(2.), 1.);
-  
-  double z = exp( -1. * u );
-  
-  // initial Energy
-  double E = sqrt(pInitial*pInitial+s_particleMasses.mass[Trk::electron]*s_particleMasses.mass[Trk::electron]);
-  
-  
-  /*
-  if ( fabs( pathLength - m_cashedPathLength ) > 1.e-6 || !m_pdf.size() ){
-
-    m_pdf = betheHeitlerPDF( pathLength );
-
-    m_cashedPathLength = pathLength;
-    
-  }
-
-  Rndm::Numbers betheHeitler( m_rndmGenSvc, Rndm::DefinedPdf( m_pdf, 0 ) );
-
-  double z = betheHeitler.shoot();
-
-  */
-
-  double deltaE(0.);
-
-  if ( direction == Trk::alongMomentum )
-    deltaE = m_scaleFactor*E * ( z - 1. );
-
-  else
-    deltaE = m_scaleFactor*E * ( 1. / z - 1. );
-    
-  return new Trk::EnergyLoss(deltaE, z);
-}
-
-std::vector<double> iFatras::McBetheHeitlerEnergyLossUpdator::betheHeitlerPDF( double pathLength ) const
-{
-
-  std::vector<double> pdf;
-
-  double c = pathLength / log(2);
-
-  double sizeOfIncrement = 1. / (double) m_numberPointsInPDF;
-
-  double currentZ(0.);
-
-  int index(0);
-
-  for( ; index < m_numberPointsInPDF ; ++index ){
-    double pdfEntry = pow( -1. * log( currentZ ), c - 1. ) / CLHEP::RandGamma::shoot(m_randomEngine, c, 1.);
-    pdf.push_back( pdfEntry );
-    currentZ += sizeOfIncrement;
-  }
-
-  return pdf;
-
-}
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McEnergyLossUpdator.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McEnergyLossUpdator.cxx
index 9c85c5cde374c37049b13c2ec0b5cb3f96069029..b3313722438dda4d40601076226d8535ffdcecd5 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McEnergyLossUpdator.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McEnergyLossUpdator.cxx
@@ -24,8 +24,6 @@ iFatras::McEnergyLossUpdator::McEnergyLossUpdator( const std::string& type, cons
   AthAlgTool( type, name, parent ),
   m_energyLossUpdator("Trk::EnergyLossUpdator/AtlasEnergyLossUpdator" ),
   m_energyLossDistribution(2),
-  m_dedicatedElectronUpdator(true),
-  m_elEnergyLossUpdator("iFatras::McBetheHeitlerEnergyLossUpdator/FatrasBetheHeitlerEnergyLossUpdator" ),
   m_rndGenSvc("AtDSFMTGenSvc", name),
   m_randomEngine(0),
   m_randomEngineName("FatrasRnd")
@@ -33,9 +31,6 @@ iFatras::McEnergyLossUpdator::McEnergyLossUpdator( const std::string& type, cons
   declareInterface<IEnergyLossUpdator>(this);
   // heavy particles energy loss
   declareProperty( "EnergyLossUpdator",                 m_energyLossUpdator);
-  // dedicated electron updates
-  declareProperty( "UseElectronUpdator",                m_dedicatedElectronUpdator );
-  declareProperty( "ElectronEnergyLossUpdator",         m_elEnergyLossUpdator);
   // random number service
   declareProperty( "RandomNumberService",               m_rndGenSvc);
   declareProperty( "RandomStreamName",                  m_randomEngineName,     "Name of the random number stream");
@@ -55,16 +50,6 @@ StatusCode iFatras::McEnergyLossUpdator::initialize()
     return StatusCode::FAILURE;
   }
 
-
-  // Retrieve the dedicated electron energz loss updator
-  if (m_dedicatedElectronUpdator){
-    // Retrieve the energy loss updator tool
-    if ( m_elEnergyLossUpdator.retrieve().isFailure() ){
-      ATH_MSG_FATAL( "Could not retrieve " << m_elEnergyLossUpdator );
-      return StatusCode::FAILURE;
-    }  
-  }
-
   // get the random generator serice
    if (m_rndGenSvc.retrieve().isFailure()){
         ATH_MSG_FATAL( "Could not retrieve " << m_rndGenSvc );
@@ -108,7 +93,7 @@ Trk::EnergyLoss* iFatras::McEnergyLossUpdator::energyLoss(
                    bool) const
 {
 
-  double simulatedDeltaE = 0.;
+  bool mpvSwitch = m_energyLossDistribution<2 ? false : true;
  
   // get the number of the material effects distribution
   Trk::EnergyLoss* sampledEloss = m_energyLossUpdator->energyLoss( 
@@ -117,64 +102,37 @@ Trk::EnergyLoss* iFatras::McEnergyLossUpdator::energyLoss(
                                           pathCorrection,
                                           direction,
                                           particleHypothesis,
-                                          true);
+                                          mpvSwitch);     
 
-  
-  double energyLoss      = 0.;
-  double energyLossSigma = 0.;
 
-  double m     = s_particleMasses.mass[particleHypothesis];
-  double E     = sqrt(momentum*momentum+m*m);
-  
-  // get the sampled energy loss
-  if(sampledEloss){
-
-    // get the energy loss and its sigma 
-    // for gauss: mean, sigma
-    // for landau: mpv, sigma
-    energyLoss      = fabs(sampledEloss->deltaE());
-    energyLossSigma = sampledEloss->sigmaDeltaE();
-    // memory cleanup
-    delete sampledEloss;
-  }
+  if (!sampledEloss) return 0; 
 
+  // smear according to preselected distribution
   switch (m_energyLossDistribution) {
     // no straggling
-    case 0 : { simulatedDeltaE += energyLoss; } break;
+    case 0 : { } break;
     // gaussian smearing
-    case 1 : { simulatedDeltaE += energyLoss + energyLossSigma * CLHEP::RandGaussZiggurat::shoot(m_randomEngine); } break;
+    case 1 : { 
+      float deIoni = sampledEloss->sigmaIoni() * CLHEP::RandGaussZiggurat::shoot(m_randomEngine);
+      float deRad  = sampledEloss->sigmaRad() * CLHEP::RandGaussZiggurat::shoot(m_randomEngine);
+      sampledEloss->update(deIoni,0.,deRad,0.,false);
+    } break;
     // landau smearing
     default : {
-       simulatedDeltaE += (energyLoss+energyLossSigma*CLHEP::RandLandau::shoot(m_randomEngine));  
-   
+      float deIoni = -sampledEloss->sigmaIoni() * CLHEP::RandLandau::shoot(m_randomEngine);  // TODO :check sign
+      float deRad  = -sampledEloss->sigmaRad() * CLHEP::RandLandau::shoot(m_randomEngine);   // TODO :check sign
+      sampledEloss->update(deIoni,0.,deRad,0.,false);   
     } break;
   }
 
-  // transform into negative nergyloss
-  simulatedDeltaE *= direction;
-
-  /* ST radiative corrections treated separately           
-  // it is an electron and has radiative corrections
-  if (m_dedicatedElectronUpdator && particleHypothesis==Trk::electron) {
-       // !< @ todo introduce cut for the calculation of bremsstrahlung  
-       Trk::EnergyLoss* radiationLoss = m_elEnergyLossUpdator->energyLoss(
-                materialProperties,
-                momentum,
-                pathCorrection,
-                direction,
-                particleHypothesis);
-       // add the simulated bethe heitler energy loss
-       double radiationDeltaE = radiationLoss ? radiationLoss->deltaE() : 0.;
-       
-       simulatedDeltaE += (-1*radiationDeltaE);
-       delete radiationLoss;
-  }
-  */
+  // protection due to straggling - maximum energy loss is E-m
+  double m     = s_particleMasses.mass[particleHypothesis];
+  double E     = sqrt(momentum*momentum+m*m);
 
-  // protection due to straggling - maximum energy loss is E
-  simulatedDeltaE = simulatedDeltaE*simulatedDeltaE > E*E ? E : simulatedDeltaE;
-  
-  ATH_MSG_VERBOSE( "[+] FatrasEnergyUpdator created random deltaP as : " << -1.*simulatedDeltaE );
+  if (sampledEloss->deltaE()+E<m ) {    // particle stopping - rest energy
+      float dRad_rest = m-E-sampledEloss->deltaE();
+      sampledEloss->update(0.,0.,dRad_rest,0.,false);   
+  }
 
-  return new Trk::EnergyLoss( -1.*simulatedDeltaE, 0. );
+  return sampledEloss;
 }
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsEngine.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsEngine.cxx
index 83b5e76867635ed2bbe7dbd4848c338093f2de7d..3f9888685cad482a6d22fa77802f7a897e551264 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsEngine.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsEngine.cxx
@@ -10,64 +10,62 @@
 #include "ISF_FatrasTools/McMaterialEffectsEngine.h"
 
 // Gaudi Kernel
-#include "GaudiKernel/IRndmGenSvc.h"
-#include "GaudiKernel/RndmGenerators.h"
 #include "GaudiKernel/DataSvc.h"
 #include "GaudiKernel/SmartDataPtr.h"
+
 // ISF includes
 #include "ISF_Interfaces/IParticleBroker.h"
 #include "ISF_Interfaces/ITruthSvc.h"
 #include "ISF_Event/ISFParticle.h"
 #include "ISF_Event/ISFTruthIncident.h"
-#include "ISF_Event/ParticleClipboard.h"
 #include "ISF_Event/ParticleUserInformation.h"
 // iFatras
-// #include "ISF_FatrasInterfaces/IHadronicInteractionProcessor.h"
-// #include "ISF_FatrasInterfaces/IProcessSamplingTool.h"
-// #include "ISF_FatrasInterfaces/IPhysicsValidationTool.h"
-// #include "ISF_FatrasInterfaces/IPhotonConversionTool.h"
-// #include "ISF_FatrasInterfaces/IParticleDecayer.h"
-// FastSimulation
-// #include "FastSimulationEvent/GenParticleEnergyDepositMap.h"
+#include "ISF_FatrasInterfaces/IHadronicInteractionProcessor.h"
+#include "ISF_FatrasInterfaces/IProcessSamplingTool.h"
+#include "ISF_FatrasInterfaces/IPhysicsValidationTool.h"
+#include "ISF_FatrasInterfaces/IParticleDecayHelper.h"
+#include "ISF_FatrasInterfaces/IEnergyLossSampler.h"
+#include "ISF_FatrasInterfaces/IMultipleScatteringSampler.h"
 // Trk inlcude
-#include "TrkExInterfaces/IEnergyLossUpdator.h"
-#include "TrkExInterfaces/IMultipleScatteringUpdator.h"
 #include "TrkParameters/TrackParameters.h"
 #include "TrkEventPrimitives/ParamDefs.h"
 #include "TrkSurfaces/Surface.h" 
 #include "TrkDetDescrInterfaces/ITrackingGeometrySvc.h"
-#include "TrkGeometry/Layer.h"
 #include "TrkGeometry/TrackingGeometry.h"
 #include "TrkGeometry/TrackingVolume.h"
 #include "TrkGeometry/MaterialProperties.h"
 #include "TrkVolumes/CylinderVolumeBounds.h"
 #include "TrkMaterialOnTrack/EnergyLoss.h"
+#include "TrkExEngine/ExtrapolationMacros.h"
+#include "TrkExInterfaces/ITimedExtrapolator.h"
+
 // CLHEP
 #include "CLHEP/Units/SystemOfUnits.h"
 #include "CLHEP/Matrix/Vector.h"
 #include "CLHEP/Random/RandFlat.h"
-#include "CLHEP/Random/RandPoisson.h"
 #include "CLHEP/Random/RandLandau.h"
-#include "AtlasCLHEP_RandomGenerators/RandGaussZiggurat.h"
+
 // Validation mode - TTree includes
 #include "TTree.h"
 #include "GaudiKernel/ITHistSvc.h" 
 // STD
 #include <math.h>
 
-// temporary
-#include "TrkGeometry/TrackingVolume.h"
-
 // constructor
 iFatras::McMaterialEffectsEngine::McMaterialEffectsEngine(const std::string& t, const std::string& n, const IInterface* p) :
   AthAlgTool(t,n,p),
+  m_samplingTool(""),
   m_eLoss(true),
-  m_eLossUpdator("iFatras::McEnergyLossUpdator/FatrasEnergyLossUpdator"),
+  m_eLossSampler(""),
   m_ms(true),
-  m_msUpdator("Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator"),  
+  m_msSampler(""),
+  m_particleDecayHelper(""),  
+  m_parametricScattering(true),
+  m_uniformHertzDipoleAngle(false),
+  m_processCode(3),
   m_minimumMomentum(50.*CLHEP::MeV),
-  m_use_msUpdator(false),
-  m_referenceMaterial(true),
+  m_minimumBremPhotonMomentum(50.*CLHEP::MeV),
+  m_createBremPhoton(true),
   m_bendingCorrection(false),
   m_rndGenSvc("AtDSFMTGenSvc", n),
   m_randomEngine(0),
@@ -75,24 +73,50 @@ iFatras::McMaterialEffectsEngine::McMaterialEffectsEngine(const std::string& t,
   m_trackingGeometry(0),
   m_trackingGeometrySvc("AtlasTrackingGeometrySvc", n),
   m_trackingGeometryName("AtlasTrackingGeometry"),
+  m_validationMode(false),
+  m_validationTool(""),
   m_particleBroker("ISF_ParticleParticleBroker", n),
   m_truthRecordSvc("ISF_TruthRecordSvc", n),
-  m_layer(0)
+  m_oneOverThree(1./3.),
+  m_projectionFactor(sqrt(2.)/2.)
 {
   declareInterface<Trk::IMaterialEffectsEngine>(this);
-  // the tool parameters -----------------------------------------------------
+
+  // steering of the screen outoput (SOP)
+  declareProperty("OutputPrefix"                        , m_sopPrefix);
+  declareProperty("OutputPostfix"                       , m_sopPostfix);
+
+  // Tool Parameters 
+  // Energy Loss Samplers
   declareProperty("EnergyLoss"                          , m_eLoss);
-  declareProperty("EnergyLossUpdator"                   , m_eLossUpdator);
+  declareProperty("EnergyLossSampler"                   , m_eLossSampler);
+  // Multiple Scattering Sampler
   declareProperty("MultipleScattering"                  , m_ms);
-  declareProperty("MultipleScatteringUpdator"           , m_msUpdator);
-  // the steering --------------------------------------------------------------
-  declareProperty("UseMultipleScatteringUpdator"        , m_use_msUpdator);
+  declareProperty("MultipleScatteringSampler"           , m_msSampler);
+  // tool handle for the particle decayer
+  declareProperty( "ParticleDecayHelper",       m_particleDecayHelper      );  
+  // Process sampling
+  declareProperty( "ProcessSamplingTool",                m_samplingTool             );
+
+  // MC Truth Properties
+  declareProperty("BremProcessCode"                     , m_processCode, "MCTruth Physics Process Code");
+  
+  // The Steering
+  declareProperty("ParametericScattering"               , m_parametricScattering);
   declareProperty("MomentumCut"                         , m_minimumMomentum);
+  declareProperty("MinimumBremPhotonMomentum"           , m_minimumBremPhotonMomentum);
+  declareProperty("CreateBremPhotons"                   , m_createBremPhoton);
+  declareProperty("BendingCorrection"                   , m_bendingCorrection);
+
+  // Validation mode
+  declareProperty("ValidationMode"                      , m_validationMode);
+  declareProperty("PhysicsValidationTool"               , m_validationTool);
+
   // TrackingGeometry Service      
-  declareProperty("TrackingGeometrySvc",                  m_trackingGeometrySvc);     
+  declareProperty("TrackingGeometrySvc"                 , m_trackingGeometrySvc);     
   declareProperty("RandomNumberService"                 , m_rndGenSvc               , "Random number generator");
   declareProperty("RandomStreamName"                    , m_randomEngineName        , "Name of the random number stream");
-
+  
   // ISF Services and Tools
   declareProperty("ParticleBroker"                      , m_particleBroker        , "ISF Particle Broker Svc");
   declareProperty("TruthRecordSvc"                      , m_truthRecordSvc        , "ISF Particle Truth Svc");      
@@ -107,414 +131,811 @@ iFatras::McMaterialEffectsEngine::~McMaterialEffectsEngine()
 StatusCode iFatras::McMaterialEffectsEngine::initialize()
 {
 
-  ATH_MSG_INFO( "initialize()" );
+  ATH_MSG_INFO( ""<<"init"<<""<<"starting initialize()" );
     
-  // retrieve the energy loss updator
+  // retrieve the energy loss sampler
   if (m_eLoss){
-    if (m_eLossUpdator.retrieve().isFailure()){
-      ATH_MSG_FATAL( "Could not retrieve " << m_eLossUpdator );
+    ATH_MSG_VERBOSE(""<<"init"<<""<<"Running WITH EnergyLossSampler ");
+    if (m_eLossSampler.retrieve().isFailure()){
+      ATH_MSG_FATAL("Could not retrieve " << m_eLossSampler );
       return StatusCode::FAILURE;
-    } else
-      ATH_MSG_VERBOSE( "Successfully retrieved " << m_eLossUpdator );
-  }
-    
-  // retrieve the multiple scattering updator tool
-  if (m_ms && m_use_msUpdator){
-    if (m_msUpdator.retrieve().isFailure()){
-      ATH_MSG_FATAL( "Could not retrieve " << m_msUpdator );
+    } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_eLossSampler );
+  } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Running WITHOUT EnergyLossSampler ");
+  
+  // retrieve the multiple scattering sampler tool
+  if (m_ms){
+    ATH_MSG_VERBOSE(""<<"init"<<""<<"Running WITH MultipleScatteringSamper ");
+    if (m_msSampler.retrieve().isFailure()){
+      ATH_MSG_FATAL( "Could not retrieve " << m_msSampler );
       return StatusCode::FAILURE;
-    } else
-      ATH_MSG_VERBOSE( "Successfully retrieved " << m_msUpdator );
-  }
-    
+    } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_msSampler );
+  } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Running WITHOUT MultipleScatteringSamper ");
+
+   // retrieve the process sampling tool
+  if (m_samplingTool.retrieve().isFailure()){
+    ATH_MSG_FATAL( "Could not retrieve " << m_samplingTool );
+    return StatusCode::FAILURE;
+  } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_samplingTool );
+  
+   // retrieve the decayHelper
+  if (m_particleDecayHelper.retrieve().isFailure()){
+    ATH_MSG_FATAL( "Could not retrieve " << m_particleDecayHelper );
+    return StatusCode::FAILURE;
+  } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_particleDecayHelper );
+  
   // get the random generator service
   if (m_rndGenSvc.retrieve().isFailure()){
     ATH_MSG_FATAL( "Could not retrieve " << m_rndGenSvc );
     return StatusCode::FAILURE;
   } else
-    ATH_MSG_VERBOSE( "Successfully retrieved " << m_rndGenSvc );
-    
-  //Get own engine with own seeds:
+    ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_rndGenSvc );
+  
+  // get own engine with own seeds:
   m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
   if (!m_randomEngine) {
     ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
     return StatusCode::FAILURE;
-  }    
-         
+  } else
+    ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully got random engine '" << m_randomEngineName << "'" );
+  
   // get the tracking geometry for layer lookup     
   // get the TrackingGeometrySvc
   if (m_trackingGeometrySvc.retrieve().isSuccess()){
-    ATH_MSG_INFO( "Successfully retrieved " << m_trackingGeometrySvc );
+    ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_trackingGeometrySvc );
     m_trackingGeometryName = m_trackingGeometrySvc->trackingGeometryName();
   } else {
     ATH_MSG_WARNING( "Couldn't retrieve " << m_trackingGeometrySvc << ". " );
     ATH_MSG_WARNING( " -> Trying to retrieve default '" << m_trackingGeometryName << "' from DetectorStore." );
-  }         
-   
+  }     
+  
   // ISF Services
   if (m_particleBroker.retrieve().isFailure()){
     ATH_MSG_FATAL( "Could not retrieve " << m_particleBroker );
     return StatusCode::FAILURE;
-  }
+  } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_particleBroker );
+  
   if (m_truthRecordSvc.retrieve().isFailure()){
     ATH_MSG_FATAL( "Could not retrieve " << m_truthRecordSvc );
     return StatusCode::FAILURE;
+  } else ATH_MSG_VERBOSE(""<<"init"<<""<<"Successfully retrieved " << m_truthRecordSvc );
+
+  if (m_validationMode){
+    // retrieve the physics validation tool
+    if (m_validationTool.retrieve().isFailure()){
+      ATH_MSG_FATAL( "Could not retrieve " << m_validationTool );
+      return StatusCode::FAILURE;
+    } else
+      ATH_MSG_VERBOSE( "Successfully retrieved " << m_validationTool );
   }
 
-   return StatusCode::SUCCESS;
+  return StatusCode::SUCCESS;
 }
 
 // finalize
 StatusCode iFatras::McMaterialEffectsEngine::finalize()
 {
-  ATH_MSG_INFO( "finalize() successful" );
+  ATH_MSG_INFO(""<<"fini "<<""<<"finalize() successful" );    
   return StatusCode::SUCCESS;
 }
 
-Trk::ExtrapolationCode iFatras::McMaterialEffectsEngine::handleMaterial(Trk::ExCellCharged& eCell,
+Trk::ExtrapolationCode iFatras::McMaterialEffectsEngine::handleMaterial(Trk::ExCellCharged& ecCharged,
 									Trk::PropDirection dir,
 									Trk::MaterialUpdateStage matupstage) const
-{
-  m_layer = eCell.leadLayer;
-
-  // get the material properties 
-  m_matProp =  0;
+{ 
+  // ATH_MSG_DEBUG(++ecCharged.navigationStep, "handleMaterial"<<"char"<<"handleMaterial for charge particle called."); 
+  return handleMaterialT<Trk::TrackParameters> (ecCharged, dir, matupstage);
   
-  if (m_referenceMaterial){
-    if (m_layer && m_layer->layerMaterialProperties()) {
-      // get the LayerMaterialProperties
-      const Trk::LayerMaterialProperties* layerMaterial = m_layer->layerMaterialProperties();
-      m_matProp = layerMaterial ? layerMaterial->fullMaterial( eCell.leadParameters->position() ) : 0;
-    }
-  }
+}
 
-  // the Extrapolator made sure that the layer is the lead layer && the parameters are the lead parameters
-  if (eCell.leadLayer && eCell.leadLayer->layerMaterialProperties()){
-    ATH_MSG_DEBUG( "handleMaterial for TrackParameters.");
-    // update the track parameters   
-    
-    eCell.leadParameters = updateTrackParameters(*eCell.leadParameters,eCell,dir,matupstage);
-  }
+Trk::ExtrapolationCode iFatras::McMaterialEffectsEngine::handleMaterial(Trk::ExCellNeutral& ecNeutral, 
+									Trk::PropDirection dir,
+									Trk::MaterialUpdateStage matupstage) const
+{ 
+  //ATH_MSG_DEBUG(++ecNeutral.navigationStep, "handleMaterial"<<"neut"<<"handleMaterial for neutral particle called."); 
+  return handleMaterialT<Trk::NeutralParameters> (ecNeutral, dir, matupstage); 
+}
 
+
+void iFatras::McMaterialEffectsEngine::multipleScatteringUpdate(const Trk::TrackParameters& pars,
+								AmgVector(5)& parameters,
+								double simTheta, double num_deltaPhi) const
+{
   
+  // parametric scattering - independent in x/y 
+  if (m_parametricScattering){ 
+    ATH_MSG_VERBOSE("[msupdate]"<<"MultipleScatteringUpdate"<<""<<"Using parametric scattering." );
+    // the initial values
+    double theta =  parameters[Trk::theta];
+    double phi   =  parameters[Trk::phi];
+    double sinTheta   = (theta*theta > 10e-10) ? sin(theta) : 1.; 
+    
+    // sample them in an independent way
+    double deltaTheta = m_projectionFactor*simTheta;
+    double deltaPhi   = m_projectionFactor*num_deltaPhi/sinTheta; 
+    
+    phi += deltaPhi;
+    if (phi >= M_PI) phi -= M_PI;
+    else if (phi < -M_PI) phi += M_PI;
+    if (theta > M_PI) theta -= M_PI;
+    
+    ATH_MSG_VERBOSE("[msupdate]"<<"MultipleScatteringUpdate"<<""<<"deltaPhi / deltaTheta = " << deltaPhi << " / " << deltaTheta );
+    
+    // assign the new values
+    parameters[Trk::phi]   = phi;   
+    parameters[Trk::theta] = fabs(theta + deltaTheta);
 
-  return Trk::ExtrapolationCode::InProgress;
-}
+  } else {
+    double thetaMs = simTheta;
+    double psi     = 2.*M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
+    // more complex but "more true" - 
+    CLHEP::Hep3Vector parsMomHep( pars.momentum().x(), pars.momentum().y(), pars.momentum().z() );
+    CLHEP::Hep3Vector newDirectionHep( parsMomHep.unit().x(), parsMomHep.unit().y(), parsMomHep.unit().z());
+    double x = -newDirectionHep.y();
+    double y = newDirectionHep.x();
+    double z = 0.;
+    // if it runs along the z axis - no good ==> take the x axis
+    if (newDirectionHep.z()*newDirectionHep.z() > 0.999999)       
+        x = 1.; y=0.;
+    // deflector direction
+    CLHEP::Hep3Vector deflector(x,y,z);
+    // rotate the new direction for scattering
+    newDirectionHep.rotate(thetaMs, deflector);
+    // and arbitrarily in psi             
+    newDirectionHep.rotate(psi, parsMomHep);
+
+    ATH_MSG_VERBOSE("[msupdate]"<<"MultipleScatteringUpdate"<<""<<"deltaPsi / deltaTheta = " << psi << " / " << thetaMs );
+
+    // assign the new values
+    parameters[Trk::phi]   = newDirectionHep.phi();   
+    parameters[Trk::theta] = newDirectionHep.theta();
+  }
 
+}
 
-const Trk::TrackParameters* iFatras::McMaterialEffectsEngine::updateTrackParameters(  const Trk::TrackParameters& parm,
-										      Trk::ExCellCharged& eCell,
-										      // const Trk::Layer& lay,
-										      // Trk::TimeLimit& timeLim, Trk::PathLimit& pathLim,
-										      // Trk::GeometrySignature /*geoID*/,
-										      Trk::PropDirection dir,
-										      Trk::MaterialUpdateStage matupstage) const
-                                                                                    // Trk::ParticleHypothesis particle) const
-{   
+void iFatras::McMaterialEffectsEngine::recordBremPhoton(const ISF::ISFParticle* parent,
+							double time,
+							double pElectron,
+							double gammaE,
+							const Amg::Vector3D& vertex,
+							Amg::Vector3D& particleDir,
+							Trk::ParticleHypothesis particle) const
+{
+  ISF::ISFParticle *bremPhot = bremPhoton(parent,time,pElectron,gammaE,vertex,particleDir,particle);
+  m_particleBroker->push(bremPhot, parent);
 
-  double matFraction = 0.;
+}
 
-  const Trk::TrackParameters* tParameters = &(parm);
+void iFatras::McMaterialEffectsEngine::recordBremPhotonLay(const ISF::ISFParticle* parent,
+							   double time,
+							   double pElectron,
+							   double gammaE,
+							   const Amg::Vector3D& vertex,
+							   Amg::Vector3D& particleDir,
+							   Trk::ParticleHypothesis particle,
+							   Trk::PropDirection dir,
+							   float matFraction ) const {
+
+  ISF::ISFParticle *bremPhot = bremPhoton(parent,time,pElectron,gammaE,vertex,particleDir,particle);
+
+  // process the photon on layer 
+  if (gammaE<m_minimumMomentum) return;
+  Trk::PathLimit pLim = m_samplingTool->sampleProcess(gammaE,0,Trk::photon);
+
+  // save presampled information
+  ISF::ParticleUserInformation* childInfo =  bremPhot->getUserInformation();
+  if (!childInfo) {
+    childInfo = new ISF::ParticleUserInformation();
+    bremPhot->setUserInformation(childInfo);
+  }
+  childInfo->setMaterialLimit(pLim.process,pLim.x0Max,0.); 
+      
+  // material fraction : flip if direction of propagation changed
+  float ci = m_layer->surfaceRepresentation().normal().dot( particleDir );
+  float co = m_layer->surfaceRepresentation().normal().dot( bremPhot->momentum().unit() );
+  float remMat =  ci*co <0 ? (1-matFraction)    : matFraction;
+
+  Trk::NeutralCurvilinearParameters  nParm(bremPhot->position(),bremPhot->momentum(),bremPhot->charge());
+  Trk::ExtrapolationCell< Trk::NeutralParameters > enc(nParm);
+  enc.leadLayer = m_layer;
+       
+  if (pLim.x0Max>0) {
+    enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
+    enc.materialLimitX0 = pLim.x0Max;
+  }
+  enc.materialProcess = pLim.process;
+  enc.materialX0 = 0.;
+  
+  // loop back      
+  processMaterialOnLayer(bremPhot,enc,dir,remMat);	
 
-  // get parent particle
-  const ISF::ISFParticle *isp = ISF::ParticleClipboard::getInstance().getParticle();
-  // something is seriously wrong if there is no parent particle
-  assert(isp);
+}
 
-  m_isp = isp;
+ISF::ISFParticle* iFatras::McMaterialEffectsEngine::bremPhoton(const ISF::ISFParticle* parent,
+							       double time,
+							       double pElectron,
+							       double gammaE,
+							       const Amg::Vector3D& vertex,
+							       Amg::Vector3D& particleDir,Trk::ParticleHypothesis particle) const
+{
+  // ------------------------------------------------------
+  // simple approach
+  // (a) simulate theta uniform within the opening angle of the relativistic Hertz dipole
+  //      theta_max = 1/gamma
+  // (b)Following the Geant4 approximation from L. Urban -> encapsulate that later
+  //      the azimutal angle
+    
+  double psi    =  2.*M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
+    
+  // the start of the equation
+  double theta = 0.;
+  double m = m_particleMasses.mass[particle];
+  double E = sqrt(pElectron*pElectron + m*m);
+
+  if (m_uniformHertzDipoleAngle) {
+    // the simplest simulation
+    theta = m/E * CLHEP::RandFlat::shoot(m_randomEngine);  
+  } else {
+    // -----> 
+    theta = m/E;
+    // follow 
+    double a = 0.625; // 5/8
+    
+    double r1 = CLHEP::RandFlat::shoot(m_randomEngine);
+    double r2 = CLHEP::RandFlat::shoot(m_randomEngine);
+    double r3 = CLHEP::RandFlat::shoot(m_randomEngine);
+    
+    double u =  -log(r2*r3)/a;
+    
+    theta *= (r1 < 0.25 ) ? u : u*m_oneOverThree; // 9./(9.+27) = 0.25
+  }
   
-  //std::cout << "updateTrackParameters : processing isp:position within layer: "<<isp <<","<< isp->generation() <<","<< particle <<std::endl;
-  //std::cout << "position: global, within layer:"<<parm->position()<<","<< matFraction<< std::endl;
+  ATH_MSG_VERBOSE("[ brem ]"<<"BremPhoton"<<""<<"Simulated angle to electron    = " << theta << "." );
   
-  // recalculate if missing
-  m_matProp = m_matProp ? m_matProp : m_layer->fullUpdateMaterialProperties(*tParameters);
-  double pathCorrection = m_layer->surfaceRepresentation().pathCorrection(tParameters->position(),dir*(tParameters->momentum()));
-  //pathCorrection = pathCorrection > 0. ? pathCorrection : m_layer->pathCorrection(parm); 
+  double th = particleDir.theta()-theta;
+  double ph = particleDir.phi();
+  if ( th<0.) { th *=-1; ph += M_PI; }
+  CLHEP::Hep3Vector newDirectionHep( sin(th)*cos(ph),sin(th)*sin(ph),cos(th) );
+  CLHEP::Hep3Vector particleDirHep( particleDir.x(), particleDir.y(), particleDir.z() );
+  newDirectionHep.rotate(psi,particleDirHep);
+  Amg::Vector3D newDirection( newDirectionHep.x(), newDirectionHep.y(), newDirectionHep.z() );
   
-  // check if a bending correction has to be applied
-  if (m_bendingCorrection) {
-    ATH_MSG_WARNING("BendingCorrection not implemented!! (McMaterialEffectsEngine.cxx)");
-    // const Trk::TrackingVolume* enclosingVolume = m_bendingCorrection ? m_layer->enclosingTrackingVolume() : 0;
-    // if (enclosingVolume && enclosingVolume->bendingCorrector() ) { 
-    //   double bendingCorrection = enclosingVolume->bendingCorrector()->bendingCorrection(*parm);
-    //   pathCorrection *= bendingCorrection; 
-    // }
-  }
+  // recoil / save input momentum for validation
+  Amg::Vector3D inEl(pElectron*particleDir);    
+  particleDir = (particleDir*pElectron- gammaE*newDirection).unit();
+     
+  // -------> create the brem photon <--------------------
+  ISF::ISFParticle *bremPhoton = new ISF::ISFParticle( vertex,
+						       gammaE*newDirection,
+						       0,   //!< mass
+						       0,   //!< charge
+						       22,  //!< pdg code
+						       time,  //!< time
+						       *parent );
   
-  //--------------------------------------------------------------------------------------------------  
-  if (msgLvl(MSG::VERBOSE) && int(dir)){
-    const Trk::TrackingVolume* enclosingVolume = m_layer->enclosingTrackingVolume();
-    std::string volumeName = enclosingVolume ? enclosingVolume->volumeName() : "Unknown";
-    double layerR = m_layer->surfaceRepresentation().bounds().r();
-    double layerZ = m_layer->surfaceRepresentation().center().z();   
-    ATH_MSG_VERBOSE( "  [M] Material effects update() on layer with index "<< m_layer->layerIndex() );
-    ATH_MSG_VERBOSE( "                        -> path/X0 on layer [r/z] = [ " << layerR << " / " << layerZ << " ] :"     
-		     << pathCorrection*m_matProp->thicknessInX0() );
-    ATH_MSG_VERBOSE( "                        -> path correctin factor  =   " << pathCorrection );
+  // register TruthIncident
+  ISF::ISFParticleVector children(1, bremPhoton);
+  ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(*parent),
+			       children,
+			       m_processCode,
+			       parent->nextGeoID(),
+			       ISF::fPrimarySurvives );
+  m_truthRecordSvc->registerTruthIncident(truth);
+
+  if (m_validationMode) {
+    ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+    validInfo->setProcess(m_processCode);
+    if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+    else validInfo->setGeneration(1);     // assume parent is a primary track
+    bremPhoton->setUserInformation(validInfo);
+
+    // save interaction info 
+    if ( m_validationTool ) {
+      Amg::Vector3D* nMom = new Amg::Vector3D(inEl);
+      m_validationTool->saveISFVertexInfo(m_processCode, vertex,*parent,inEl+gammaE*newDirection,nMom,children);
+      delete nMom; 
+    }
+
+
   }
-  //--------------------------------------------------------------------------------------------------
+
+  return bremPhoton;
+  
+} 
+
+Trk::ExtrapolationCode iFatras::McMaterialEffectsEngine::processMaterialOnLayer( const ISF::ISFParticle* isp,
+							       Trk::ExCellCharged& eCell,
+							       Trk::PropDirection dir,
+							       float& mFraction) const
+{   
+
+  const Trk::TrackParameters* parm = eCell.leadParameters;
+    
+  // path correction
+  double pathCorrection = fabs(m_layer->surfaceRepresentation().pathCorrection(parm->position(),dir*(parm->momentum())));
   
   // figure out if particle stopped in the layer and recalculate path limit
   int iStatus = 0;
-  double dX0 = (1.-matFraction)*pathCorrection*m_matProp->thicknessInX0();
+  float dX0 = (1.-mFraction)*pathCorrection*m_thicknessInX0;
+  float dL0 = (1.-mFraction)*pathCorrection*m_thicknessInL0;
+  
+  if ( eCell.materialLimitX0>0 && eCell.materialProcess<100 && eCell.materialX0+dX0>= eCell.materialLimitX0) {      // elmg. interaction
+    float x0rem = eCell.materialLimitX0 - eCell.materialX0;
+    dL0 *= x0rem>0 ? x0rem/dX0 : 1.; 
+    if ( x0rem>0 ) dX0 = x0rem;
+    iStatus = 1; 
+  } else if ( eCell.materialLimitL0>0 && eCell.materialProcess>100 && eCell.materialL0+dL0 >= eCell.materialLimitL0 )   {     // hadronic interaction
+    float l0rem = eCell.materialLimitX0 - eCell.materialL0 ;
+    dX0 *= l0rem>0 ? l0rem/dL0 : 1.;
+    if ( l0rem>0 ) dL0 = l0rem;
+    iStatus = 2; 
+  }
+  // material update
+  eCell.materialX0 += dX0;
+  eCell.materialL0 += dL0;
+  eCell.zOaTrX     += m_matProp->zOverAtimesRho()*dX0;
+  eCell.zX         += m_matProp->averageZ()*dX0;
   
   // get the kinematics
-  double p    = (tParameters->momentum()).mag();
+  double p    = parm->momentum().mag();
+  double m    = m_particleMasses.mass[eCell.pHypothesis];
+  double E    = sqrt(p*p+m*m);
   
-  matFraction += dX0/pathCorrection/m_matProp->thicknessInX0();  
+  // radiation and ionization preceed the presampled interaction (if any) 
   
-  if ( isp->charge()!=0 ) {
-    AmgVector(5) updatedParameters(tParameters->parameters());  
-    if ( m_eLoss ) ionize(*tParameters, updatedParameters, dX0, dir, eCell.pHypothesis );
+  if ( m_eLoss ) {
+    // the updatedParameters - first a deep copy
+    AmgVector(5)      uParameters = parm->parameters();
 
-    if ( m_ms ) {
+    // smeared/presampled energy loss
+    Trk::EnergyLoss* eloss = m_eLossSampler->energyLoss(*m_matProp, p, dX0/m_matProp->thicknessInX0(), dir, eCell.pHypothesis);
 
-      double sigmaMSproj = (m_use_msUpdator && m_msUpdator ) ?
-	sqrt(m_msUpdator->sigmaSquare(*m_matProp, p, dX0/m_matProp->thicknessInX0(), eCell.pHypothesis)) : msSigma(dX0,p,eCell.pHypothesis);
- 
-      multipleScatteringUpdate(*tParameters,updatedParameters,sigmaMSproj, pathCorrection);
+    if (eCell.pHypothesis==Trk::electron && m_createBremPhoton) { 
+
+      // ionization update
+     
+      double newP = E+eloss->meanIoni()>m ? sqrt((E+eloss->meanIoni())*(E+eloss->meanIoni())-m*m) : 0.5*m_minimumMomentum;
+      uParameters[Trk::qOverP] = parm->charge()/newP;
+
+      // radiation 
+      if (newP>m_minimumMomentum)
+	radiate(isp,uParameters,eCell,dX0,mFraction,dir,pathCorrection*m_thicknessInX0);   // mFraction used to estimate material thickness for brem photons
+
+      // save the actual radiation loss
+      float nqOp = uParameters[Trk::qOverP];
+      float radLoss = fabs(1./nqOp) - newP;
+      eloss->update(0.,0.,radLoss-eloss->meanRad(),eloss->meanRad()-radLoss);
+
+    } else {
+      
+      // calculate the new momentum
+      double newP = E+eloss->deltaE()>m ? sqrt((E+eloss->deltaE())*(E+eloss->deltaE())-m*m) : 0.5*m_minimumMomentum;
+      uParameters[Trk::qOverP] = parm->charge()/newP;
+
+    }
+
+    // TODO straggling 
+
+    if (m_validationMode && eloss) {
+      if (eCell.eLoss) { 
+	eCell.eLoss->update(*eloss);
+	delete eloss;
+      } else 
+        eCell.eLoss=eloss;
     }
+
+    
+    const Trk::TrackParameters* upd = parm->associatedSurface().createTrackParameters(uParameters[0],
+										      uParameters[1],
+										      uParameters[2],
+										      uParameters[3],
+										      uParameters[4]);
+    //eCell.updateLeadParameters(upd);   
+    eCell.leadParameters = upd;    
+
+    if (upd->momentum().mag() < m_minimumMomentum ) {
+
+      // save info for locally created particle
+      if (m_validationMode && isp!=m_isp) {
+	ATH_MSG_VERBOSE( "  saving interaction info for locally produced particle " << isp->pdgCode() );
+	m_validationTool->saveISFParticleInfo(*isp,eCell,Trk::ExtrapolationCode::SuccessMaterialLimit); 
+      }
+
+      if (isp!=m_isp) { delete isp; }      
+      return Trk::ExtrapolationCode::FailureUpdateKill;
+    }
+  }
+  
+  mFraction += dX0/pathCorrection/m_thicknessInX0;  
+  
+  if ( m_ms ) {
+    AmgVector(5) updatedParameters=eCell.leadParameters->parameters();  
+    
+    double simTheta = m_msSampler->simTheta(*m_matProp, p, dX0/m_thicknessInX0, eCell.pHypothesis);
+    //do the update -> You need 2 evaluation of simTheta. The second one is used to calculate deltaphi in multipleScatteringUpdate
+    multipleScatteringUpdate(*(eCell.leadParameters), updatedParameters, simTheta, 
+			     m_msSampler->simTheta(*m_matProp, p, dX0/m_thicknessInX0, eCell.pHypothesis));
+    
+    
     
     // use the manipulator to update the track parameters -------> get rid of 0!
-    tParameters = tParameters->associatedSurface().createTrackParameters(updatedParameters[0],
-									 updatedParameters[1],
-									 updatedParameters[2],
-									 updatedParameters[3],
-									 updatedParameters[4],
-									 0);
+    const Trk::TrackParameters* upd = eCell.leadParameters->associatedSurface().createTrackParameters(updatedParameters[0],
+												      updatedParameters[1],
+												      updatedParameters[2],
+												      updatedParameters[3],
+												      updatedParameters[4]);
+    
+    //eCell.updateLeadParameters(upd); 
+    eCell.leadParameters=upd; 
+    if (upd->momentum().mag() < m_minimumMomentum ) {
+      if (isp!=m_isp) { delete isp;}
+      return Trk::ExtrapolationCode::FailureUpdateKill;
+    }
+  }
+  
+  if ( iStatus==1 || iStatus==2 ) {   // interaction with particle stopping
+    
+    ISF::ISFParticleVector childs = m_samplingTool->interact(isp,eCell);    // TODO pass material when needed
+          
+    // save info for locally created particles
+    if (m_validationMode && isp!=m_isp) {
+      ATH_MSG_VERBOSE( "  saving interaction info for locally produced particle " << isp->pdgCode() );
+      m_validationTool->saveISFParticleInfo(*isp,eCell,Trk::ExtrapolationCode::SuccessMaterialLimit); 
+    }
+    
+    // loop over childrens and decide about their fate
     
-    if ((tParameters->momentum()).mag() < m_minimumMomentum ) {
-      if (isp!=m_isp) { delete isp; delete tParameters; }
-      return 0;
+    for (unsigned ic=0; ic<childs.size(); ic++) {
+      double mom = childs[ic]->momentum().mag();
+      
+      if (mom<m_minimumMomentum) continue;
+      Trk::ParticleHypothesis pHypothesis = m_pdgToParticleHypothesis.convert(childs[ic]->pdgCode(),childs[ic]->charge());
+      Trk::PathLimit pLim = m_samplingTool->sampleProcess(mom,childs[ic]->charge(),pHypothesis);
+      double pathLimit = ( !m_particleDecayHelper.empty()) ? m_particleDecayHelper->freePath(*childs[ic]) : -1.; 
+      
+      // TODO sample decays and save the material collection & path limits at the exit from the layer (ISFFatrasParticle ?)
+      
+      // material fraction : flip if direction of propagation changed
+      float ci = m_layer->surfaceRepresentation().normal().dot( parm->momentum().unit() );
+      float co = m_layer->surfaceRepresentation().normal().dot( childs[ic]->momentum().unit() );
+      float remMat =  ci*co <0 ? (1-mFraction)    : mFraction;
+      
+      // save presampled information
+      ISF::ParticleUserInformation* childInfo =  childs[ic]->getUserInformation();
+      if (!childInfo) {
+	childInfo = new ISF::ParticleUserInformation();
+	childs[ic]->setUserInformation(childInfo);
+      }
+      childInfo->setMaterialLimit(pLim.process,pLim.x0Max,0.); 
+      //std::cout <<"child info saved on isp:"<<childs[ic]<<","<<childs[ic]->getUserInformation()->materialLimit()<< std::endl;
+
+      // configure child cell and loop back
+      if (childs[ic]->charge()!=0) {
+	Trk::CurvilinearParameters  cParm(childs[ic]->position(),childs[ic]->momentum(),childs[ic]->charge());
+	Trk::ExtrapolationCell< Trk::TrackParameters > ecc(cParm);
+	
+	if (pathLimit>0) {
+	  ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithPathLimit);
+	  ecc.pathLimit = pathLimit;
+	}
+	
+	if (pLim.x0Max>0) {
+	  if (pLim.process==121) {
+	    ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitL0);
+	    ecc.materialLimitL0 = pLim.x0Max;
+	  } else {
+	    ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
+	    ecc.materialLimitX0 = pLim.x0Max;
+	  }
+	  ecc.materialProcess = pLim.process;
+	}
+        ecc.leadLayer = m_layer;
+	
+	// loop back      
+	Trk::ExtrapolationCode exitCode=processMaterialOnLayer(childs[ic],ecc,dir,remMat);
+  
+        if (exitCode == Trk::ExtrapolationCode::SuccessMaterialLimit )
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "stopped in layer" );
+        else 
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "leaving layer" ); 
+
+      } else {
+	Trk::NeutralCurvilinearParameters  nParm(childs[ic]->position(),childs[ic]->momentum(),childs[ic]->charge());
+	Trk::ExtrapolationCell< Trk::NeutralParameters > enc(nParm);
+	
+	if (pathLimit>0) {
+	  enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithPathLimit);
+	  enc.pathLimit = pathLimit;
+	}
+       
+	if (pLim.x0Max>0) {
+	  if (pLim.process==121) {
+	    enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitL0);
+	    enc.materialLimitL0 = pLim.x0Max;
+	  } else {
+	    enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
+	    enc.materialLimitX0 = pLim.x0Max;
+	  }
+	 enc.materialProcess = pLim.process;
+	}
+        enc.leadLayer = m_layer;
+
+	// loop back      
+	Trk::ExtrapolationCode exitCode=processMaterialOnLayer(childs[ic],enc,dir,remMat);	
+  
+        if (exitCode == Trk::ExtrapolationCode::SuccessMaterialLimit )
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "stopped in layer" );
+        else 
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "leaving layer" ); 
+      }
     }
     
+    if (childs.size()>0 || true ) { // TODO: pass the interaction status
+      if (isp!=m_isp) { delete isp; }
+      return Trk::ExtrapolationCode::SuccessMaterialLimit;
+    }
   }
   
-  // register particle if not in the stack already
-  if (tParameters && isp!=m_isp ) {
-    ISF::ISFParticle* regisp=new ISF::ISFParticle(isp->position(),tParameters->momentum(),isp->mass(),isp->charge(),
+  // register particle if not in the stack already 
+  if (isp!=m_isp ) {
+    ISF::ISFParticle* regisp=new ISF::ISFParticle(isp->position(),parm->momentum(),isp->mass(),isp->charge(),
 						  isp->pdgCode(),isp->timeStamp(),*m_isp,isp->barcode());
+    // add presampled process info 
+    if (isp->getUserInformation() && isp->getUserInformation()->materialLimit()) {
+      ISF::MaterialPathInfo* matLim = isp->getUserInformation()->materialLimit();
+      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      validInfo->setMaterialLimit(matLim->process,matLim->dMax,matLim->process==121 ? eCell.materialL0 : eCell.materialX0);
+      regisp->setUserInformation(validInfo);
+      //std::cout <<"collected material at layer exit:"<<regisp->getUserInformation()->materialLimit()->dCollected<<std::endl;
+    }
+    // validation mode
+    if (m_validationMode) {
+      ISF::ParticleUserInformation* validInfo = regisp->getUserInformation();
+      if (!validInfo){
+	validInfo = new ISF::ParticleUserInformation();
+	regisp->setUserInformation(validInfo);
+      }
+      if (isp->getUserInformation()) validInfo->setProcess(isp->getUserInformation()->process());
+      else validInfo->setProcess(-2);        // signal problem in the validation chain
+      if (isp->getUserInformation()) validInfo->setGeneration(isp->getUserInformation()->generation());
+      else validInfo->setGeneration(-1);        // signal problem in the validation chain
+    }
     m_particleBroker->push(regisp, m_isp);
   }
-  
   if (isp!=m_isp) delete isp;
+
+  return Trk::ExtrapolationCode::InProgress;   
+}
+
+Trk::ExtrapolationCode iFatras::McMaterialEffectsEngine::processMaterialOnLayer( const ISF::ISFParticle* isp,
+							       Trk::ExCellNeutral& eCell,
+							       Trk::PropDirection dir,
+							       float& mFraction) const
+{   
+
+  const Trk::NeutralParameters* parm = eCell.leadParameters;
+    
+  // path correction
+  double pathCorrection = fabs(m_layer->surfaceRepresentation().pathCorrection(parm->position(),dir*(parm->momentum())));
   
-  if (tParameters) std::cout <<"layer "<< tParameters->position()<< " returns :"<< isp <<" with momentum  "<< tParameters->momentum().mag()  << std::endl;
-  else std::cout <<"layer returns :"<<  0  << std::endl;
+  // figure out if particle stopped in the layer and recalculate path limit
+  int iStatus = 0;
+  float dX0 = (1.-mFraction)*pathCorrection*m_thicknessInX0;
+  float dL0 = (1.-mFraction)*pathCorrection*m_thicknessInL0;
   
-  return (&parm); 
+  if ( eCell.materialLimitX0>0 && eCell.materialProcess<100 && eCell.materialX0+dX0>= eCell.materialLimitX0) {      // elmg. interaction
+    float x0rem = eCell.materialLimitX0 - eCell.materialX0;
+    dL0 *= x0rem>0 ? x0rem/dX0 : 1.; 
+    if ( x0rem>0 ) dX0 = x0rem;
+    iStatus = 1; 
+  } else if ( eCell.materialLimitL0>0 && eCell.materialProcess>100 && eCell.materialL0+dL0 >= eCell.materialLimitL0 )   {     // hadronic interaction
+    float l0rem = eCell.materialLimitX0 - eCell.materialL0 ;
+    dX0 *= l0rem>0 ? l0rem/dL0 : 1.;
+    if ( l0rem>0 ) dL0 = l0rem;
+    iStatus = 2; 
+  }
+  // material update
+  eCell.materialX0 += dX0;
+  eCell.materialL0 += dL0;
+  eCell.zOaTrX     += m_matProp->zOverAtimesRho()*dX0;
+  eCell.zX         += m_matProp->averageZ()*dX0;
   
-}
-
-void iFatras::McMaterialEffectsEngine::ionize(const Trk::TrackParameters& parm, 
-					      AmgVector(5)& updatedPar,
-					      double dInX0,
-					      Trk::PropDirection /*dir*/,
-					      Trk::ParticleHypothesis particle ) const 
-{
-  double p    = parm.momentum().mag();                                                      
-  double m    = m_particleMasses.mass[particle];
-  double E    = sqrt(p*p+m*m);
+  // get the kinematics
+  //double p    = parm->momentum().mag();
+  //double m    = m_particleMasses.mass[eCell.pHypothesis];
+  //double E    = sqrt(p*p+m*m);
+    
+  if ( iStatus==1 || iStatus==2 ) {   // interaction with particle stopping
+    
+    ISF::ISFParticleVector childs = m_samplingTool->interact(isp,eCell);     // TODO pass material when needed
+    
+    // save info for locally created particles
+    if (m_validationMode && isp!=m_isp) {
+      ATH_MSG_VERBOSE( "  saving interaction info for locally produced particle " << isp->pdgCode() );
+      m_validationTool->saveISFParticleInfo(*isp,eCell,Trk::ExtrapolationCode::SuccessMaterialLimit); 
+    }
+    
+    // loop over childrens and decide about their fate
+    
+    for (unsigned ic=0; ic<childs.size(); ic++) {
+      double mom = childs[ic]->momentum().mag();
+      
+      if (mom<m_minimumMomentum) continue;
+      Trk::ParticleHypothesis pHypothesis = m_pdgToParticleHypothesis.convert(childs[ic]->pdgCode(),childs[ic]->charge());
+      Trk::PathLimit pLim = m_samplingTool->sampleProcess(mom,childs[ic]->charge(),pHypothesis);
+      double pathLimit = ( !m_particleDecayHelper.empty()) ? m_particleDecayHelper->freePath(*childs[ic]) : -1.; 
+      
+      // TODO sample decays and save the material collection & path limits at the exit from the layer (ISFFatrasParticle ?)
+      
+      // material fraction : flip if direction of propagation changed
+      float ci = m_layer->surfaceRepresentation().normal().dot( parm->momentum().unit() );
+      float co = m_layer->surfaceRepresentation().normal().dot( childs[ic]->momentum().unit() );
+      float remMat =  ci*co <0 ? (1-mFraction)    : mFraction;
+
+      // save presampled information
+      ISF::ParticleUserInformation* childInfo =  childs[ic]->getUserInformation();
+      if (!childInfo) {
+	childInfo = new ISF::ParticleUserInformation();
+	childs[ic]->setUserInformation(childInfo);
+      }
+      childInfo->setMaterialLimit(pLim.process,pLim.x0Max,0.); 
+      
+      // configure child cell and loop back
+      if (childs[ic]->charge()!=0) {
+	Trk::CurvilinearParameters  cParm(childs[ic]->position(),childs[ic]->momentum(),childs[ic]->charge());
+	Trk::ExtrapolationCell< Trk::TrackParameters > ecc(cParm);
+	
+	if (pathLimit>0) {
+	  ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithPathLimit);
+	  ecc.pathLimit = pathLimit;
+	}
+	
+	if (pLim.x0Max>0) {
+	  if (pLim.process==121) {
+	    ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitL0);
+	    ecc.materialLimitL0 = pLim.x0Max;
+	  } else {
+	    ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
+	    ecc.materialLimitX0 = pLim.x0Max;
+	  }
+	  ecc.materialProcess = pLim.process;
+	}
+	
+	// loop back      
+	Trk::ExtrapolationCode exitCode = processMaterialOnLayer(childs[ic],ecc,dir,remMat);
   
-  // the following formulas are imported from STEP
-  // preparation of kinetic constants
-
-  double me    = m_particleMasses.mass[Trk::electron];
-  double mfrac = me/m;
-  double beta  = p/E;
-  double gamma = E/m;
-  double Ionization = 0.;
-
-  //Ionization - Bethe-Bloch
-  double I = 16.e-6 * std::pow(m_matProp->averageZ(),0.9); //16 eV * Z**0.9 - bring to MeV
-
-  //K/A*Z = 0.5 * 30.7075MeV/(g/mm2) * Z/A * rho[g/mm3]  / scale to mm by this
-  double kaz = 0.5*30.7075*m_matProp->zOverAtimesRho();
-
-  if (particle == Trk::electron){
-    // for electrons use slightly different BetheBloch adaption
-    // see Stampfer, et al, "Track Fitting With Energy Loss", Comp. Pyhs. Comm. 79 (1994), 157-164
-    Ionization = -kaz*(2.*log(2.*me/I)+3.*log(gamma) - 1.95);
+        if (exitCode == Trk::ExtrapolationCode::SuccessMaterialLimit )
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "stopped in layer" );
+        else 
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "leaving layer" ); 
+
+      } else {
+	Trk::NeutralCurvilinearParameters  nParm(childs[ic]->position(),childs[ic]->momentum(),childs[ic]->charge());
+	Trk::ExtrapolationCell< Trk::NeutralParameters > enc(nParm);
+	
+	if (pathLimit>0) {
+	  enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithPathLimit);
+	  enc.pathLimit = pathLimit;
+	}
+       
+	if (pLim.x0Max>0) {
+	  if (pLim.process==121) {
+	    enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitL0);
+	    enc.materialLimitL0 = pLim.x0Max;
+	  } else {
+	    enc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
+	    enc.materialLimitX0 = pLim.x0Max;
+	  }
+	 enc.materialProcess = pLim.process;
+	}
+	
+	// loop back      
+	Trk::ExtrapolationCode exitCode = processMaterialOnLayer(childs[ic],enc,dir,remMat);	
+
+        if (exitCode == Trk::ExtrapolationCode::SuccessMaterialLimit )
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "stopped in layer" );
+        else 
+	  ATH_MSG_VERBOSE(" child particle:"<< ic << "leaving layer" ); 
+      }
+    }
+    
+    if (childs.size()>0 || true) { // TODO : pass the interaction status 
+      if (isp!=m_isp) { delete isp; }
+      return Trk::ExtrapolationCode::SuccessMaterialLimit;
+    }
   }
-  else {
-    double eta2 = beta*gamma; eta2 *= eta2;
-    // density effect, only valid for high energies (gamma > 10 -> p > 1GeV for muons)
-    double delta = 0.;
-    if (gamma > 10.) {
-      double eplasma = 28.816e-6 * sqrt(1000.*m_matProp->zOverAtimesRho());
-      delta = 2.*log(eplasma/I) + log(eta2) - 1.;
+  
+  // register particle if not in the stack already
+  if (isp!=m_isp ) {
+    ISF::ISFParticle* regisp=new ISF::ISFParticle(isp->position(),parm->momentum(),isp->mass(),isp->charge(),
+						  isp->pdgCode(),isp->timeStamp(),*m_isp,isp->barcode());
+    // add presampled process info 
+    if (isp->getUserInformation() && isp->getUserInformation()->materialLimit()) {
+      ISF::MaterialPathInfo* matLim = isp->getUserInformation()->materialLimit();
+      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      validInfo->setMaterialLimit(matLim->process,matLim->dMax,matLim->process==121 ? eCell.materialL0 : eCell.materialX0);
+      regisp->setUserInformation(validInfo);
+    }
+    // validation mode
+    if (m_validationMode) {
+      ISF::ParticleUserInformation* validInfo = regisp->getUserInformation();
+      if (!validInfo){
+	validInfo = new ISF::ParticleUserInformation();
+	regisp->setUserInformation(validInfo);
+      }
+      if (isp->getUserInformation()) validInfo->setProcess(isp->getUserInformation()->process());
+      else validInfo->setProcess(-2);        // signal problem in the validation chain
+      if (isp->getUserInformation()) validInfo->setGeneration(isp->getUserInformation()->generation());
+      else validInfo->setGeneration(-1);        // signal problem in the validation chain
     }
-    // tmax - cut off energy
-    double tMax = 2.*eta2*me/(1.+2.*gamma*mfrac+mfrac*mfrac);
-    // divide by beta^2 for non-electrons
-    kaz /= beta*beta;
-    Ionization = -kaz*(log(2.*me*eta2*tMax/(I*I)) - 2.*(beta*beta) - delta);
+    m_particleBroker->push(regisp, m_isp);
   }
- 
-  double energyLoss = Ionization*dInX0*m_matProp->x0();   
-  double newP = sqrt(fmax(0.,(E+energyLoss)*(E+energyLoss)-m*m));       
-
-  newP = newP <= 0.5*m_minimumMomentum ? 0.5*m_minimumMomentum : newP;      // arbitrary regularization;
+  if (isp!=m_isp) delete isp;
   
-  (updatedPar)[Trk::qOverP] = parm.charge()/newP; 
-
+  return Trk::ExtrapolationCode::InProgress;   
 }
 
-double iFatras::McMaterialEffectsEngine::msSigma(double dInX0,double p,Trk::ParticleHypothesis particle) const {
-   
-  double m    = m_particleMasses.mass[particle];
-  double E    = sqrt(p*p+m*m);
-  double beta = p/E; 
 
-  // PDG Particle Review, Phys.Rev.D86,010001(2012), chapter 30.3, page 328 
+// radiative effects
+void iFatras::McMaterialEffectsEngine::radiate(const ISF::ISFParticle* parent, AmgVector(5)& parm ,
+					       Trk::ExCellCharged& eCell, float pathLim, float mFr,
+					       Trk::PropDirection dir, float refX) const {
+ 
+  // sample energy loss and free path independently
+  double path = 0.;
+  double p = 1./ fabs(parm[Trk::qOverP]);
 
-  double sigmaMSproj = 13.6/beta/p*sqrt(dInX0)*(1.+0.038*log(dInX0));
+  Amg::Vector3D eDir = eCell.leadParameters->momentum().unit();
+  Amg::Vector3D ePos = eCell.leadParameters->position();
 
-  return sigmaMSproj; 
-} 
-                                                         
-void iFatras::McMaterialEffectsEngine::multipleScatteringUpdate(const Trk::TrackParameters& pars,
-								AmgVector(5)& parameters,
-                                                                double sigmaMSproj, double pathCorrection) const
-{
-  //block of initial values
-  //------------------------------------//
-  double d = 0.1*m_matProp->thickness(); //layer thickness, cm
-  d*=pathCorrection;
-  double X0 = 0.1*m_matProp->x0(); //layer rad len, cm
-  double Z = m_matProp->averageZ(); //charge layer material
-  //double AN = 2*Z; //mass number of the material (an approximation, bad for heavy nuclei)
-  double p = m_isp->momentum().mag()*0.001; //particle momentum, GeV
-  double m = m_isp->mass()*0.001; //particle mass, GeV
-  double dOverX0 = d/X0;
-  double E=sqrt(p*p+m*m);
-  double beta=p/E;
-  double scale = 0.860176; ///magic
-  
-  std::cout<<"McMaterialEffectsEngine::multipleScatteringUpdate: Material pars (d,beta,p,dOverX0,Z): "<<std::endl;
-  std::cout<<d<<' '<<beta<<' '<<p<<' '<<dOverX0<<' '<<Z<<std::endl;
-  //-----------------------------------//
-  
-  double theta = simulate_theta_space(beta, p, dOverX0, Z, scale);
-  //theta*=m_projectionFactor*sigmaMSproj;
-  
-  double psi = 2*M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
-  
-  CLHEP::Hep3Vector parsMomHep( pars.momentum().x(), pars.momentum().y(), pars.momentum().z() );
-  CLHEP::Hep3Vector newDirection( parsMomHep.unit().x(), parsMomHep.unit().y(), parsMomHep.unit().z());
-  double x = -newDirection.y();
-  double y = newDirection.x();
-  double z = 0.;
-  // if it runs along the z axis - no good ==> take the x axis
-  if (newDirection.z()*newDirection.z() > 0.999999) {
-    x=1.; y=0.;
-  }
-  // deflector direction
-  CLHEP::Hep3Vector deflector(x,y,z);
-  // rotate the new direction for scattering
-  newDirection.rotate(theta, deflector);
-  // and arbitrarily in psi             
-  newDirection.rotate(psi, parsMomHep);
-  // assign the new values
-  parameters[Trk::phi]   = newDirection.phi();   
-  parameters[Trk::theta] = newDirection.theta();
-  
-}
+  while ( path < pathLim && p>m_minimumMomentum ) {
 
-double iFatras::McMaterialEffectsEngine::simulate_theta_space(double beta, double p,double dOverX0,double Z, double scale) const{
-  double * scattering_params;
-    // Decide which mixture is best
-  if (dOverX0/(beta*beta)>0.6/pow(Z,0.6)){ //Gaussian
-    // Gaussian mixture or pure Gaussian
-    if (dOverX0/(beta*beta)>10){
-        scattering_params=get_gaussian(beta,p,dOverX0,scale); // Get parameters
-        std::cout<<"McMaterialEffectsEngine::multipleScatteringUpdate: using pure_gaussian"<<std::endl;
-    }
-    else{
-        scattering_params=get_gaussmix(beta,p,dOverX0,Z,scale); // Get parameters
-        std::cout<<"McMaterialEffectsEngine::multipleScatteringUpdate: using gaussian_mixture"<<std::endl;
-    }
-    return sim_gaussmix(scattering_params); // Simulate
-  }
-  //Semigaussian mixture
-  scattering_params = get_semigauss(beta,p,dOverX0,Z,scale); // Get parameters
-  std::cout<<"McMaterialEffectsEngine::multipleScatteringUpdate: using semi_gaussian mixture"<<std::endl;
-  return sim_semigauss(scattering_params); // Simulate
-}
+    double rndx = CLHEP::RandFlat::shoot(m_randomEngine);
 
-double * iFatras::McMaterialEffectsEngine::get_gaussian(double beta, double p,double dOverX0, double scale) const{
-  double * scattering_params = new double[4];
-  scattering_params[0]=0.015/beta/p*sqrt(dOverX0)*scale; //Total standard deviation of mixture
- // scattering_params[0]=1.0;
-  scattering_params[1]=1.0; //Variance of core
-  scattering_params[2]=1.0; //Variance of tails
-  scattering_params[3]=0.5; //Mixture weight of tail component
-  return scattering_params;
-}
+    // sample visible fraction of the mother momentum taken according to 1/f  
+ 
+    double eps = fmin(10.,m_minimumMomentum)/p;
 
-double * iFatras::McMaterialEffectsEngine::get_gaussmix(double beta, double p,double dOverX0,double Z, double scale) const{  
-  double * scattering_params = new double[4];
-  scattering_params[0]=0.015/beta/p*sqrt(dOverX0)*scale; //Total standard deviation of mixture
-//   scattering_params[0]=1.0;
-  double d1=log(dOverX0/(beta*beta));
-  double d2=log(pow(Z,2.0/3.0)*dOverX0/(beta*beta));
-  double epsi;
-  double var1=(-1.843e-3*d1+3.347e-2)*d1+8.471e-1; //Variance of core
-  if (d2<0.5)
-    epsi=(6.096e-4*d2+6.348e-3)*d2+4.841e-2;
-  else
-    epsi=(-5.729e-3*d2+1.106e-1)*d2-1.908e-2;
-  scattering_params[1]=var1; //Variance of core
-  scattering_params[2]=(1-(1-epsi)*var1)/epsi; //Variance of tails
-  scattering_params[3]=epsi; //Mixture weight of tail component
-  return scattering_params;
-}
+    double z = pow(eps,pow(rndx,exp(1.1)));          // adjustment here ? 
 
-double * iFatras::McMaterialEffectsEngine::get_semigauss(double beta,double p,double dOverX0,double Z, double scale) const{
-  double * scattering_params = new double[6];
-  double N=dOverX0*1.587E7*pow(Z,1.0/3.0)/(beta*beta)/(Z+1)/log(287/sqrt(Z));
-  scattering_params[4]=0.015/beta/p*sqrt(dOverX0)*scale; //Total standard deviation of mixture
-//  double eps = 0.125*log10(10*dOverX0);
-//  scattering_params[4]=0.0175/beta/p*sqrt(dOverX0)*(1+eps);
-  //scattering_params[4]= 0.0192/beta/p*sqrt(dOverX0)*(1.+0.038*log(dOverX0));
-  //scattering_params[4]=1.0;
-  double rho=41000/pow(Z,2.0/3.0);
-  double b=rho/sqrt(N*(log(rho)-0.5));
-  double n=pow(Z,0.1)*log(N);
-  double var1=(5.783E-4*n+3.803E-2)*n+1.827E-1;
-  double a=(((-4.590E-5*n+1.330E-3)*n-1.355E-2)*n+9.828E-2)*n+2.822E-1;
-  double epsi = (1-var1)/(a*a*(log(b/a)-0.5)-var1);
-  scattering_params[3]=(epsi>0) ? epsi : 0.0;//Mixture weight of tail component
-  scattering_params[0]=a; //Parameter 1 of tails
-  scattering_params[1]=b; //Parameter 2 of tails
-  scattering_params[2]=var1; //Variance of core
-  scattering_params[5]=N; //Average number of scattering processes
-  return scattering_params;
-}
+    // convert into scaling factor for mother momentum
+    z = (1.- z); 
 
-double iFatras::McMaterialEffectsEngine::sim_gaussmix(double * scattering_params) const{
-  double sigma_tot = scattering_params[0];
-  double var1 = scattering_params[1];
-  double var2 = scattering_params[2];
-  double epsi = scattering_params[3];  
-  bool ind = (double)rand()/RAND_MAX>epsi;
-  double u=(double)rand()/RAND_MAX;
-  if(ind)
-  return sqrt(var1)*sqrt(-2*log(u))*sigma_tot;
-  else
-  return sqrt(var2)*sqrt(-2*log(u))*sigma_tot;
-}
+    // turn into path   
+    //double dx = -log(z)*0.65;     // adjust for mean of exp(-x)  
+    double dx = -0.7*log(z);     // adjust for mean of exp(-x)  
+ 
+    // sample free path (in X0)
+    //double rnd = CLHEP::RandFlat::shoot(m_randomEngine);
+    //double dx = -log(rnd)/13.;
+
+    // resolve the case when there is not enough material left in the layer
+    if ( path+dx > pathLim ) {
+      double rndp = CLHEP::RandFlat::shoot(m_randomEngine);
+      if (rndp > (pathLim-path)/dx){        
+	(parm)[Trk::qOverP] = (parm)[Trk::qOverP]>0 ? 1/p : -1/p; 
+	mFr += (pathLim-path)/refX; 
+        path = pathLim;
+	break;                   // radiation loop ended         
+      } 
+      path += dx*rndp;
+      mFr += dx*rndp/refX; 
+      
+    } else { 
+      path+=dx;
+      mFr += dx/refX; 
+    }
+    if ( p*(1-z) > m_minimumBremPhotonMomentum ) {
+
+      double deltaP = (1-z)*p;
+      recordBremPhotonLay(parent,eCell.time,p,deltaP,ePos,eDir,eCell.pHypothesis,dir,mFr);
+      p *=z ;
+
+      // std::cout <<"brem photon emitted, momentum update:"<< p<<","<<path<<","<<pathLim<<",mat.fraction:"<<mFr<<std::endl; 
+    }    
+  }
 
-double iFatras::McMaterialEffectsEngine::sim_semigauss(double * scattering_params) const{
-  double a = scattering_params[0];
-  double b = scattering_params[1];
-  double var1 = scattering_params[2];
-  double epsi = scattering_params[3];
-  double sigma_tot = scattering_params[4];
-  bool ind=(double)rand()/RAND_MAX>epsi;
-  double u=(double)rand()/RAND_MAX;
-  if(ind)
-  return sqrt(var1)*sqrt(-2*log(u))*sigma_tot;
-  else
-  return a*b*sqrt((1-u)/(u*b*b+a*a))*sigma_tot;
+  (parm)[Trk::qOverP] = (parm)[Trk::qOverP] > 0 ? 1/p : -1./p; 
+  (parm)[Trk::theta]  = eDir.theta(); 
+  (parm)[Trk::phi]    = eDir.phi(); 
+  return; 
 }
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsUpdator.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsUpdator.cxx
index 949c0320a11fcd53ffc70398770a987309f85455..eaca07196a0a8383fe0df9196d07aa5fe1d7af75 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsUpdator.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/McMaterialEffectsUpdator.cxx
@@ -21,7 +21,7 @@
 #include "ISF_Event/ISFTruthIncident.h"
 #include "ISF_Event/ParticleClipboard.h"
 #include "ISF_Event/ParticleUserInformation.h"
-#include "ISF_FatrasInterfaces/IParticleDecayer.h"
+#include "ISF_FatrasInterfaces/IParticleDecayHelper.h"
 // iFatras
 #include "ISF_FatrasInterfaces/IHadronicInteractionProcessor.h"
 #include "ISF_FatrasInterfaces/IProcessSamplingTool.h"
@@ -140,7 +140,7 @@ iFatras::McMaterialEffectsUpdator::McMaterialEffectsUpdator(const std::string& t
       declareProperty("ProcessSamplingTool"                 , m_samplingTool);
       declareProperty("PhotonConversionTool"                , m_conversionTool);
       // tool handle for the particle decayer
-      declareProperty( "ParticleDecayer"                    , m_particleDecayer      );
+      declareProperty( "ParticleDecayHelper"                , m_particleDecayer      );
       // MC Truth Properties
       declareProperty("BremProcessCode"                     , m_processCode, "MCTruth Physics Process Code");
       // the steering --------------------------------------------------------------
@@ -485,9 +485,20 @@ const Trk::TrackParameters* iFatras::McMaterialEffectsUpdator::updateInLay(const
     if (parm && isp!=m_isp ) {
       ISF::ISFParticle* regisp=new ISF::ISFParticle(isp->position(),parm->momentum(),isp->mass(),isp->charge(),
 						  isp->pdgCode(),isp->timeStamp(),*m_isp,isp->barcode());
-    // in the validation mode, add process info
-      if (m_validationMode) {
+      // add presampled process info 
+      if (isp->getUserInformation() && isp->getUserInformation()->materialLimit()) {
+	ISF::MaterialPathInfo* matLim = isp->getUserInformation()->materialLimit();
 	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+	validInfo->setMaterialLimit(matLim->process,matLim->dMax,matLim->process==121 ? pathLim.l0Collected : pathLim.x0Collected);
+	regisp->setUserInformation(validInfo);
+      }
+      // in the validation mode, add process info
+      if (m_validationMode) {
+	ISF::ParticleUserInformation* validInfo = regisp->getUserInformation();
+        if (!validInfo) {
+	  validInfo = new ISF::ParticleUserInformation();
+	  regisp->setUserInformation(validInfo);
+	}
 	if (isp->getUserInformation()) validInfo->setProcess(isp->getUserInformation()->process());
 	else validInfo->setProcess(-2);        // signal problem in the validation chain
 	if (isp->getUserInformation()) validInfo->setGeneration(isp->getUserInformation()->generation());
@@ -575,7 +586,8 @@ const Trk::TrackParameters* iFatras::McMaterialEffectsUpdator::updateInLay(const
   if ( iStatus==1 || iStatus==2 ) {   // interaction
     
     ISF::ISFParticleVector childs = iStatus==1 ? interactLay(isp,timeLim.time,*parm,particle,pathLim.process) :
-                                                 m_hadIntProcessor->doHadIntOnLayer(isp,timeLim.time,*parm,m_extMatProp, particle);
+      m_hadIntProcessor->doHadIntOnLayer(isp, timeLim.time, parm->position(), parm->momentum(),
+					 ( m_extMatProp ? &m_extMatProp->material() : 0), particle);
 
     // save info for locally created particles
     if (m_validationMode && childs.size()>0 && isp!=m_isp) {
@@ -615,15 +627,25 @@ const Trk::TrackParameters* iFatras::McMaterialEffectsUpdator::updateInLay(const
   if (parm && isp!=m_isp ) {
     ISF::ISFParticle* regisp=new ISF::ISFParticle(isp->position(),parm->momentum(),isp->mass(),isp->charge(),
 						  isp->pdgCode(),isp->timeStamp(),*m_isp,isp->barcode());
+    // add presampled process info 
+    if (isp->getUserInformation() && isp->getUserInformation()->materialLimit()) {
+      ISF::MaterialPathInfo* matLim = isp->getUserInformation()->materialLimit();
+      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      validInfo->setMaterialLimit(matLim->process,matLim->dMax,matLim->process==121 ? pathLim.l0Collected : pathLim.x0Collected);
+      regisp->setUserInformation(validInfo);
+    }
     // in the validation mode, add process info
     if (m_validationMode) {
-      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      ISF::ParticleUserInformation* validInfo = regisp->getUserInformation();
+      if (!validInfo){
+	validInfo = new ISF::ParticleUserInformation();
+	regisp->setUserInformation(validInfo);
+      }
       if (isp->getUserInformation()) validInfo->setProcess(isp->getUserInformation()->process());
       else validInfo->setProcess(-2);        // signal problem in the validation chain
       if (isp->getUserInformation()) validInfo->setGeneration(isp->getUserInformation()->generation());
       else validInfo->setGeneration(-1);        // signal problem in the validation chain
-      regisp->setUserInformation(validInfo);
-    }
+   }
     m_particleBroker->push(regisp, m_isp);
   }
 
@@ -860,7 +882,7 @@ const Trk::TrackParameters* iFatras::McMaterialEffectsUpdator::update(double tim
 
   // Hadronic Interaction section ----------------------------------------------------------------------------------------------
   // ST add hadronic interaction for secondaries 
-  if ( particle == Trk::pion &&  m_hadInt && m_hadIntProcessor->hadronicInteraction(parm, p, E,matprop, pathCorrection,particle)){
+  if ( particle == Trk::pion &&  m_hadInt && m_hadIntProcessor->hadronicInteraction(parm.position(), parm.momentum(), p, E, parm.charge(), matprop, pathCorrection, particle)){
       ATH_MSG_VERBOSE( "  [+] Hadronic interaction killed initial hadron ... stop simulation, tackle childs." );
       return 0;    
   } 
@@ -1500,6 +1522,7 @@ void iFatras::McMaterialEffectsUpdator::recordBremPhotonLay(const ISF::ISFPartic
                                                          timeLim.time,  //!< time
                                                          *parent );
 
+
     // in the validation mode, add process info
     if (m_validationMode) {
       ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
@@ -1612,7 +1635,7 @@ const Trk::TrackParameters*  iFatras::McMaterialEffectsUpdator::interact(double
 
   if ( process == 201 ) {    // decay  
     // update parent before decay
-    ISF::ISFParticleVector childVector = m_particleDecayer->decayParticle(*parent,position,momentum,parent->pdgCode(),time);
+    ISF::ISFParticleVector childVector = m_particleDecayer->decayParticle(*parent,position,momentum,time);
 
     for (unsigned int i=0; i<childVector.size(); i++) {
       // in the validation mode, add process info
@@ -1714,13 +1737,14 @@ const Trk::TrackParameters*  iFatras::McMaterialEffectsUpdator::interact(double
 
   if (process==14) {  // photon conversion
    
-    const Trk::TrackParameters* parm = new Trk::CurvilinearParameters(position,momentum,parent->charge());
+    const Trk::NeutralParameters* parm = new Trk::NeutralCurvilinearParameters(position,momentum,parent->charge());
 
     bool cStat = m_conversionTool->doConversion(time, *parm); 
    
-    if ( cStat ) delete parm;
-  
-    return (cStat? 0 : parm);
+    if (!cStat) ATH_MSG_WARNING( "Conversion failed, killing photon anyway ");
+
+    // kill the mother particle
+    delete parm; return 0;
   }
 
   if (process==121) {    // hadronic interaction
@@ -1729,7 +1753,7 @@ const Trk::TrackParameters*  iFatras::McMaterialEffectsUpdator::interact(double
 
     const Trk::TrackParameters* parm = new Trk::CurvilinearParameters(position,momentum,parent->charge());
 
-    bool recHad = m_hadIntProcessor->doHadronicInteraction(time,*parm,m_extMatProp, particle, true);
+    bool recHad = m_hadIntProcessor->doHadronicInteraction(time, position, momentum, m_extMatProp, particle, true);
     // eventually : bool recHad =  m_hadIntProcessor->recordHadState( time, p, position, pDir, particle);
  
     // kill the track if interaction recorded --------------------------
@@ -1823,7 +1847,29 @@ ISF::ISFParticleVector  iFatras::McMaterialEffectsUpdator::interactLay(const ISF
 
   if (process==14) {  // photon conversion
    
-    return m_conversionTool->doConversionOnLayer(parent, time, parm); 
+    Trk::NeutralCurvilinearParameters neu(position,momentum,parent->charge());
+    childVector=m_conversionTool->doConversionOnLayer(parent, time, neu); 
+
+    // validation mode 
+    if (m_validationMode && m_validationTool) {
+
+      // add process info for children
+      for (unsigned int i=0; i<childVector.size(); i++) {
+	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+	validInfo->setProcess(process);
+	if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+	else validInfo->setGeneration(1);     // assume parent is a primary track
+	childVector[i]->setUserInformation(validInfo);
+      }
+      // save interaction info 
+      if ( m_validationTool ) {
+	Amg::Vector3D* nMom = 0;
+	m_validationTool->saveISFVertexInfo(process, position,*parent,momentum,nMom,childVector);
+	delete nMom;
+      }
+    }
+  
+    return childVector;
   }
 
   if (process==121) {    // hadronic interaction
@@ -1832,12 +1878,13 @@ ISF::ISFParticleVector  iFatras::McMaterialEffectsUpdator::interactLay(const ISF
 
     const Trk::CurvilinearParameters parm(position,momentum,parent->charge());
 
-    return ( m_hadIntProcessor->doHadIntOnLayer(parent, time,parm,m_extMatProp, particle) );
+    return ( m_hadIntProcessor->doHadIntOnLayer(parent, time, position, momentum,
+						m_extMatProp? &m_extMatProp->material() : 0, particle) );
 
   }
 
   if ( process == 201 ) {    // decay  
-    childVector = m_particleDecayer->decayParticle(*parent,parm.position(),parm.momentum(),parent->pdgCode(),time);
+    childVector = m_particleDecayer->decayParticle(*parent,parm.position(),parm.momentum(),time);
     // in the validation mode, add process info
     if (m_validationMode) {
       for (unsigned int i=0; i<childVector.size(); i++) {
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerGaussianMixture.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerGaussianMixture.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c7e84d57ec2262447e8d34f73aa33f0f9aa18c9e
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerGaussianMixture.cxx
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// MultipleScatteringSamplerGaussianMixture.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+// Trk include
+#include "TrkGeometry/MaterialProperties.h"
+
+#include "ISF_FatrasTools/MultipleScatteringSamplerGaussianMixture.h"
+
+#include "AtlasCLHEP_RandomGenerators/RandGaussZiggurat.h"
+
+// static particle masses
+Trk::ParticleMasses iFatras::MultipleScatteringSamplerGaussianMixture::s_particleMasses;
+// static doubles
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_main_RutherfordScott = 13.6*Gaudi::Units::MeV;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_log_RutherfordScott  =  0.038;
+
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_main_RossiGreisen = 17.5*Gaudi::Units::MeV;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_log_RossiGreisen  =  0.125;
+
+// ============================= Gaussian mixture model =============
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixSigma1_a0  =  8.471e-1;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixSigma1_a1  =  3.347e-2;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixSigma1_a2  = -1.843e-3;
+
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixEpsilon_a0 =  4.841e-2;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixEpsilon_a1 =  6.348e-3;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixEpsilon_a2 =  6.096e-4;
+
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixEpsilon_b0 = -1.908e-2;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixEpsilon_b1 =  1.106e-1;
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_gausMixEpsilon_b2 = -5.729e-3;
+
+double iFatras::MultipleScatteringSamplerGaussianMixture::s_projectionFactor  =  sqrt(2.);
+
+// constructor
+iFatras::MultipleScatteringSamplerGaussianMixture::MultipleScatteringSamplerGaussianMixture(const std::string& t, const std::string& n, const IInterface* p) :
+  AthAlgTool(t,n,p),
+  m_log_include(true),
+  m_optGaussianMixtureG4(true),
+  m_rndGenSvc("AtRndmGenSvc", n),
+  m_randomEngine(0),
+  m_randomEngineName("TrkExRnd")
+{
+  declareInterface<IMultipleScatteringSampler>(this);
+  // multiple scattering parameters
+  declareProperty("MultipleScatteringLogarithmicTermOn", m_log_include);
+  declareProperty("G4OptimisedGaussianMixtureModel",     m_optGaussianMixtureG4);
+  // random service for Gaussian mixture model
+  declareProperty("RandomNumberService",                 m_rndGenSvc,            "Name of the random number service");
+  declareProperty("RandomStreamName",                    m_randomEngineName,     "Name of the random number stream");
+}
+
+// destructor
+iFatras::MultipleScatteringSamplerGaussianMixture::~MultipleScatteringSamplerGaussianMixture()
+{}
+
+// Athena standard methods
+// initialize
+StatusCode iFatras::MultipleScatteringSamplerGaussianMixture::initialize()
+{
+  // get the random generator service
+  if (m_rndGenSvc.retrieve().isFailure()) {
+    ATH_MSG_WARNING( "Could not retrieve " << m_rndGenSvc );
+  } else {
+    ATH_MSG_VERBOSE( "Successfully retrieved " << m_rndGenSvc );
+  }
+
+  //Get own engine with own seeds:
+  m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
+  if (!m_randomEngine) {
+    ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
+    return StatusCode::FAILURE;
+  } else
+    ATH_MSG_VERBOSE ("Successfully got random engine '" << m_randomEngineName << "'");
+  
+  ATH_MSG_VERBOSE( "Gaussian mixture model optimised = " << m_optGaussianMixtureG4 );
+
+  ATH_MSG_INFO( "initialize() successful" );
+  return StatusCode::SUCCESS;
+}
+
+// finalize
+StatusCode iFatras::MultipleScatteringSamplerGaussianMixture::finalize()
+{
+  ATH_MSG_INFO( "finalize() successful" );
+  return StatusCode::SUCCESS;
+}
+
+
+double iFatras::MultipleScatteringSamplerGaussianMixture::simTheta(const Trk::MaterialProperties& mat,
+								   double p,
+								   double pathcorrection,
+								   Trk::ParticleHypothesis particle,
+								   double ) const
+{
+  if (mat.thicknessInX0()<=0. || particle==Trk::geantino) return 0.;
+  
+  // make sure the path correction is positive to avoid a floating point exception
+  pathcorrection *= pathcorrection < 0. ? (-1.) : (1) ;
+  
+  // scale the path length to the radiation length
+  double t = pathcorrection * mat.thicknessInX0();
+
+  // kinematics (relativistic)
+  double m    = s_particleMasses.mass[particle];
+  double E    = sqrt(p*p + m*m);
+  double beta = p/E;
+  
+  double sigma2(0.);
+  
+  if (particle != Trk::electron) {
+
+    // the highland formula
+    sigma2 = s_main_RutherfordScott/(beta*p);
+
+    if (m_log_include)
+      sigma2 *= (1.+s_log_RutherfordScott*log(t));
+    
+    sigma2 *= (sigma2*t);
+  }
+  
+  else {
+    
+    // Electron multiple scattering effects - see Highland NIM 129 (1975) p497-499
+    // (Highland extension to the Rossi-Greisen formulation)
+    // NOTE: The formula can be extended by replacing the momentum^2 term with pi * pf
+    sigma2 = s_main_RossiGreisen / ( beta * p );
+    sigma2 *= (sigma2*t);
+    
+    if ( m_log_include ) {
+      double factor = 1. + s_log_RossiGreisen * log10( 10. * t );
+      factor *= factor;
+      sigma2 *= factor;
+    }
+  }
+  
+  // d_0'
+  double dprime          = t/(beta*beta);
+  double log_dprime      = log(dprime);
+  // d_0'' 
+  double log_dprimeprime = log(std::pow(mat.averageZ(),2.0/3.0) * dprime);
+  // get epsilon
+  double epsilon = log_dprimeprime < 0.5 ? 
+    s_gausMixEpsilon_a0 + s_gausMixEpsilon_a1*log_dprimeprime + s_gausMixEpsilon_a2*log_dprimeprime*log_dprimeprime :
+    s_gausMixEpsilon_b0 + s_gausMixEpsilon_b1*log_dprimeprime + s_gausMixEpsilon_b2*log_dprimeprime*log_dprimeprime;
+  // the standard sigma
+  double sigma1square = s_gausMixSigma1_a0 + s_gausMixSigma1_a1*log_dprime + s_gausMixSigma1_a2*log_dprime*log_dprime;
+  // G4 optimised / native double Gaussian model
+  if (!m_optGaussianMixtureG4) sigma2 = 225.*dprime/(p*p);
+  // throw the random number core/tail
+  if ( CLHEP::RandFlat::shoot(m_randomEngine) < epsilon) {
+    sigma2 *= (1.-(1.-epsilon)*sigma1square)/epsilon;
+  }
+  
+  return s_projectionFactor*sqrt(sigma2)*CLHEP::RandGaussZiggurat::shoot(m_randomEngine);
+  
+}
+
+
+
+
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerGeneralMixture.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerGeneralMixture.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b53a4ed8053ce488ffc498eabd3f7b776478fa8b
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerGeneralMixture.cxx
@@ -0,0 +1,224 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// MultipleScatteringSamplerGeneralMixture.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+// Trk include
+#include "TrkGeometry/MaterialProperties.h"
+
+#include "ISF_FatrasTools/MultipleScatteringSamplerGeneralMixture.h"
+#include "AtlasCLHEP_RandomGenerators/RandGaussZiggurat.h"
+
+// static particle masses
+Trk::ParticleMasses iFatras::MultipleScatteringSamplerGeneralMixture::s_particleMasses;
+// static doubles
+
+double iFatras::MultipleScatteringSamplerGeneralMixture::s_main_RossiGreisen = 17.5*Gaudi::Units::MeV;
+double iFatras::MultipleScatteringSamplerGeneralMixture::s_log_RossiGreisen  =  0.125;
+
+double iFatras::MultipleScatteringSamplerGeneralMixture::s_projectionFactor  =  sqrt(2.);
+
+// ============================= General mixture model =============
+double iFatras::MultipleScatteringSamplerGeneralMixture::s_genMixScale = 0.608236; //numerically derived scaling factor
+
+// constructor
+iFatras::MultipleScatteringSamplerGeneralMixture::MultipleScatteringSamplerGeneralMixture(const std::string& t, const std::string& n, const IInterface* p) :
+  AthAlgTool(t,n,p),
+  m_log_include(true),
+  m_rndGenSvc("AtRndmGenSvc", n),
+  m_randomEngine(0),
+  m_randomEngineName("TrkExRnd")
+{
+  declareInterface<IMultipleScatteringSampler>(this);
+  // multiple scattering parameters
+  declareProperty("MultipleScatteringLogarithmicTermOn", m_log_include);
+  // random service for Gaussian mixture model
+  declareProperty("RandomNumberService",                 m_rndGenSvc,            "Name of the random number service");
+  declareProperty("RandomStreamName",                    m_randomEngineName,     "Name of the random number stream");
+}
+
+// destructor
+iFatras::MultipleScatteringSamplerGeneralMixture::~MultipleScatteringSamplerGeneralMixture()
+{}
+
+// Athena standard methods
+// initialize
+StatusCode iFatras::MultipleScatteringSamplerGeneralMixture::initialize()
+{
+  // get the random generator service
+  if (m_rndGenSvc.retrieve().isFailure()) {
+    ATH_MSG_WARNING( "Could not retrieve " << m_rndGenSvc );
+  } else {
+    ATH_MSG_VERBOSE( "Successfully retrieved " << m_rndGenSvc );
+  }
+
+  //Get own engine with own seeds:
+  m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
+  if (!m_randomEngine) {
+    ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
+    return StatusCode::FAILURE;
+  } else
+    ATH_MSG_VERBOSE ("Successfully got random engine '" << m_randomEngineName << "'");
+  
+
+  ATH_MSG_INFO( "initialize() successful" );
+  return StatusCode::SUCCESS;
+}
+
+// finalize
+StatusCode iFatras::MultipleScatteringSamplerGeneralMixture::finalize()
+{
+  ATH_MSG_INFO( "finalize() successful" );
+  return StatusCode::SUCCESS;
+}
+
+
+double iFatras::MultipleScatteringSamplerGeneralMixture::simTheta(const Trk::MaterialProperties& mat,
+								      double p,
+								      double pathcorrection,
+								      Trk::ParticleHypothesis particle,
+								      double ) const
+{
+  if (mat.thicknessInX0()<=0. || particle==Trk::geantino) return 0.;
+  
+  // make sure the path correction is positive to avoid a floating point exception
+  pathcorrection *= pathcorrection < 0. ? (-1.) : (1) ;
+  
+  // scale the path length to the radiation length
+  double dOverX0 = pathcorrection * mat.thicknessInX0();
+
+  // kinematics (relativistic)
+  double m    = s_particleMasses.mass[particle];
+  double E    = sqrt(p*p + m*m);
+  double beta = p/E;
+  
+  //material properties
+  double Z = mat.averageZ(); //charge layer material
+
+  double sigma2(0.);
+  double theta(0.);
+  
+  
+  if (particle != Trk::electron) {
+    //----------------------------------------------------------------------------------------------//
+    //see Mixture models of multiple scattering: computation and simulation. - R.Frühwirth, M. Liendl. -
+    //Computer Physics Communications 141 (2001) 230–246
+    //----------------------------------------------------------------------------------------------//
+    double * scattering_params;
+    // Decide which mixture is best
+    if (dOverX0/(beta*beta)>0.6/pow(Z,0.6)){ //Gaussian
+      // Gaussian mixture or pure Gaussian
+      if (dOverX0/(beta*beta)>10){
+	  scattering_params=getGaussian(beta,p,dOverX0,s_genMixScale); // Get parameters
+	  //std::cout<<"MultipleScatteringSamplerGeneralMixture::multipleScatteringUpdate: using pure_gaussian"<<std::endl;
+      }
+      else{
+	  scattering_params=getGaussmix(beta,p,dOverX0,Z,s_genMixScale); // Get parameters
+	  //std::cout<<"MultipleScatteringSamplerGeneralMixture::multipleScatteringUpdate: using gaussian_mixture"<<std::endl;
+      }
+      theta = simGaussmix(scattering_params); // Simulate
+    }
+    else{
+      //Semigaussian mixture
+      scattering_params = getSemigauss(beta,p,dOverX0,Z,s_genMixScale); // Get parameters
+      //std::cout<<"MultipleScatteringSamplerGeneralMixture::multipleScatteringUpdate: using semi_gaussian mixture"<<std::endl;
+      theta = simSemigauss(scattering_params); // Simulate
+    }
+  }
+  
+  else {
+    // Electron multiple scattering effects - see Highland NIM 129 (1975) p497-499
+    // (Highland extension to the Rossi-Greisen formulation)
+    // NOTE: The formula can be extended by replacing the momentum^2 term with pi * pf
+    sigma2 = s_main_RossiGreisen / ( beta * p );
+    sigma2 *= (sigma2*dOverX0);
+    
+    if ( m_log_include ) {
+      double factor = 1. + s_log_RossiGreisen * log10( 10. * dOverX0 );
+      factor *= factor;
+      sigma2 *= factor;
+    }
+    
+    theta=sqrt(sigma2)*CLHEP::RandGaussZiggurat::shoot(m_randomEngine);
+  }
+  
+  return theta*s_projectionFactor;
+}
+
+double * iFatras::MultipleScatteringSamplerGeneralMixture::getGaussian(double beta, double p,double dOverX0, double scale) const{
+  double * scattering_params = new double[4];
+  scattering_params[0]=15./beta/p*sqrt(dOverX0)*scale; //Total standard deviation of mixture
+  scattering_params[1]=1.0; //Variance of core
+  scattering_params[2]=1.0; //Variance of tails
+  scattering_params[3]=0.5; //Mixture weight of tail component
+  return scattering_params;
+}
+
+double * iFatras::MultipleScatteringSamplerGeneralMixture::getGaussmix(double beta, double p,double dOverX0,double Z, double scale) const{  
+  double * scattering_params = new double[4];
+  scattering_params[0]=15./beta/p*sqrt(dOverX0)*scale; //Total standard deviation of mixture
+  double d1=log(dOverX0/(beta*beta));
+  double d2=log(pow(Z,2.0/3.0)*dOverX0/(beta*beta));
+  double epsi;
+  double var1=(-1.843e-3*d1+3.347e-2)*d1+8.471e-1; //Variance of core
+  if (d2<0.5)
+    epsi=(6.096e-4*d2+6.348e-3)*d2+4.841e-2;
+  else
+    epsi=(-5.729e-3*d2+1.106e-1)*d2-1.908e-2;
+  scattering_params[1]=var1; //Variance of core
+  scattering_params[2]=(1-(1-epsi)*var1)/epsi; //Variance of tails
+  scattering_params[3]=epsi; //Mixture weight of tail component
+  return scattering_params;
+}
+
+double * iFatras::MultipleScatteringSamplerGeneralMixture::getSemigauss(double beta,double p,double dOverX0,double Z, double scale) const{
+  double * scattering_params = new double[6];
+  double N=dOverX0*1.587E7*pow(Z,1.0/3.0)/(beta*beta)/(Z+1)/log(287/sqrt(Z));
+  scattering_params[4]=15./beta/p*sqrt(dOverX0)*scale; //Total standard deviation of mixture
+  double rho=41000/pow(Z,2.0/3.0);
+  double b=rho/sqrt(N*(log(rho)-0.5));
+  double n=pow(Z,0.1)*log(N);
+  double var1=(5.783E-4*n+3.803E-2)*n+1.827E-1;
+  double a=(((-4.590E-5*n+1.330E-3)*n-1.355E-2)*n+9.828E-2)*n+2.822E-1;
+  double epsi = (1-var1)/(a*a*(log(b/a)-0.5)-var1);
+  scattering_params[3]=(epsi>0) ? epsi : 0.0;//Mixture weight of tail component
+  scattering_params[0]=a; //Parameter 1 of tails
+  scattering_params[1]=b; //Parameter 2 of tails
+  scattering_params[2]=var1; //Variance of core
+  scattering_params[5]=N; //Average number of scattering processes
+  return scattering_params;
+}
+
+double iFatras::MultipleScatteringSamplerGeneralMixture::simGaussmix(double * scattering_params) const{
+  double sigma_tot = scattering_params[0];
+  double var1 = scattering_params[1];
+  double var2 = scattering_params[2];
+  double epsi = scattering_params[3];  
+  bool ind = CLHEP::RandFlat::shoot(m_randomEngine)>epsi;
+  double u=CLHEP::RandFlat::shoot(m_randomEngine);
+  if(ind)
+  return sqrt(var1)*sqrt(-2*log(u))*sigma_tot;
+  else
+  return sqrt(var2)*sqrt(-2*log(u))*sigma_tot;
+}
+
+double iFatras::MultipleScatteringSamplerGeneralMixture::simSemigauss(double * scattering_params) const{
+  double a = scattering_params[0];
+  double b = scattering_params[1];
+  double var1 = scattering_params[2];
+  double epsi = scattering_params[3];
+  double sigma_tot = scattering_params[4];
+  bool ind=CLHEP::RandFlat::shoot(m_randomEngine)>epsi;
+  double u=CLHEP::RandFlat::shoot(m_randomEngine);
+  if(ind)
+  return sqrt(var1)*sqrt(-2*log(u))*sigma_tot;
+  else
+  return a*b*sqrt((1-u)/(u*b*b+a*a))*sigma_tot;
+}
+
+
+
+
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerHighland.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerHighland.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..163fa899838871503b8624170f0ea105303c3276
--- /dev/null
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/MultipleScatteringSamplerHighland.cxx
@@ -0,0 +1,139 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// MultipleScatteringSamplerHighland.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+// Trk include
+#include "TrkGeometry/MaterialProperties.h"
+#include "TrkExUtils/MaterialInteraction.h"
+
+#include "ISF_FatrasTools/MultipleScatteringSamplerHighland.h"
+
+#include "AtlasCLHEP_RandomGenerators/RandGaussZiggurat.h"
+
+// static particle masses
+Trk::ParticleMasses iFatras::MultipleScatteringSamplerHighland::s_particleMasses;
+// static doubles
+double iFatras::MultipleScatteringSamplerHighland::s_main_RutherfordScott = 13.6*Gaudi::Units::MeV;
+double iFatras::MultipleScatteringSamplerHighland::s_log_RutherfordScott  =  0.038;
+
+double iFatras::MultipleScatteringSamplerHighland::s_main_RossiGreisen = 17.5*Gaudi::Units::MeV;
+double iFatras::MultipleScatteringSamplerHighland::s_log_RossiGreisen  =  0.125;
+
+double iFatras::MultipleScatteringSamplerHighland::s_projectionFactor  =  sqrt(2.);
+
+Trk::MaterialInteraction       m_matInt;
+
+// constructor
+iFatras::MultipleScatteringSamplerHighland::MultipleScatteringSamplerHighland(const std::string& t, const std::string& n, const IInterface* p) :
+  AthAlgTool(t,n,p),
+  m_log_include(true),
+  m_rndGenSvc("AtRndmGenSvc", n),
+  m_randomEngine(0),
+  m_randomEngineName("TrkExRnd")
+{
+  declareInterface<IMultipleScatteringSampler>(this);
+  // multiple scattering parameters
+  declareProperty("MultipleScatteringLogarithmicTermOn", m_log_include);
+  // random service
+  declareProperty("RandomNumberService",                 m_rndGenSvc,            "Name of the random number service");
+  declareProperty("RandomStreamName",                    m_randomEngineName,     "Name of the random number stream");
+}
+
+// destructor
+iFatras::MultipleScatteringSamplerHighland::~MultipleScatteringSamplerHighland()
+{}
+
+// Athena standard methods
+// initialize
+StatusCode iFatras::MultipleScatteringSamplerHighland::initialize()
+{
+
+  // get the random generator service
+  if (m_rndGenSvc.retrieve().isFailure()) {
+    ATH_MSG_WARNING( "Could not retrieve " << m_rndGenSvc );
+  } else {
+    ATH_MSG_VERBOSE( "Successfully retrieved " << m_rndGenSvc );
+  }
+  
+  //Get own engine with own seeds:
+  m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
+  if (!m_randomEngine) {
+    ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
+    return StatusCode::FAILURE;
+  } else
+    ATH_MSG_VERBOSE ("Successfully got random engine '" << m_randomEngineName << "'");
+  
+  ATH_MSG_INFO( "initialize() successful" );
+  return StatusCode::SUCCESS;
+}
+
+// finalize
+StatusCode iFatras::MultipleScatteringSamplerHighland::finalize()
+{
+  ATH_MSG_INFO( "finalize() successful" );
+  return StatusCode::SUCCESS;
+}
+
+
+double iFatras::MultipleScatteringSamplerHighland::simTheta(const Trk::MaterialProperties& mat,
+							    double p,
+							    double pathcorrection,
+							    Trk::ParticleHypothesis particle,
+							    double ) const
+{
+  if (mat.thicknessInX0()<=0. || particle==Trk::geantino) return 0.;
+  
+  // make sure the path correction is positive to avoid a floating point exception
+  pathcorrection *= pathcorrection < 0. ? (-1.) : (1) ;
+  
+  // scale the path length to the radiation length
+  double t = pathcorrection * mat.thicknessInX0();
+
+  // kinematics (relativistic)
+  double m    = s_particleMasses.mass[particle];
+  double E    = sqrt(p*p + m*m);
+  double beta = p/E;
+  
+  double sigma2(0.);
+  
+  double sigma = m_matInt.sigmaMS(t, p, beta);
+  sigma2 = sigma*sigma;
+  
+  // Code below will not be used if the parameterization of TrkUtils is used 
+  if (particle != Trk::electron) {
+
+    // the highland formula
+    sigma2 = s_main_RutherfordScott/(beta*p);
+
+    if (m_log_include)
+      sigma2 *= (1.+s_log_RutherfordScott*log(t));
+    
+    sigma2 *= (sigma2*t);
+  }
+  
+  else {
+    
+    // Electron multiple scattering effects - see Highland NIM 129 (1975) p497-499
+    // (Highland extension to the Rossi-Greisen formulation)
+    // NOTE: The formula can be extended by replacing the momentum^2 term with pi * pf
+    sigma2 = s_main_RossiGreisen / ( beta * p );
+    sigma2 *= (sigma2*t);
+    
+    if ( m_log_include ) {
+      double factor = 1. + s_log_RossiGreisen * log10( 10. * t );
+      factor *= factor;
+      sigma2 *= factor;
+    }
+  }
+  
+  return s_projectionFactor*sqrt(sigma2)*CLHEP::RandGaussZiggurat::shoot(m_randomEngine);
+  
+}
+
+
+
+
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhotonConversionTool.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhotonConversionTool.cxx
index cc5ad052f737d6bf05b306bfac04f74fa5aabd7b..ccd4af9bf42a64f3a741caf5381893055c22daab 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhotonConversionTool.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhotonConversionTool.cxx
@@ -29,11 +29,11 @@
 #include "TrkExInterfaces/IEnergyLossUpdator.h"
 #include "TrkExInterfaces/ITimedExtrapolator.h"
 #include "TrkExInterfaces/IMultipleScatteringUpdator.h"
-#include "TrkParameters/TrackParameters.h"
 #include "TrkSurfaces/Surface.h"
 #include "TrkGeometry/Layer.h"
 #include "TrkGeometry/MaterialProperties.h"
 #include "TrkVolumes/CylinderVolumeBounds.h"
+#include "TrkNeutralParameters/NeutralParameters.h"
 // CLHEP
 #include "CLHEP/Units/SystemOfUnits.h"
 #include "CLHEP/Matrix/Vector.h"
@@ -252,10 +252,10 @@ void iFatras::PhotonConversionTool::recordChilds(double time,
                                                *parent );
       // in the validation mode, add process info
       if (m_validationMode) {
-	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
         validInfo->setProcess(14);
         if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
-	else validInfo->setGeneration(1);     // assume parent is a primary track
+      	else validInfo->setGeneration(1);     // assume parent is a primary track
         ch1->setUserInformation(validInfo);
       }
       children[ichild] = ch1;
@@ -274,10 +274,10 @@ void iFatras::PhotonConversionTool::recordChilds(double time,
       
       // in the validation mode, add process info
       if (m_validationMode) {
-	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
         validInfo->setProcess(14);
-        if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
-	else validInfo->setGeneration(1);     // assume parent is a primary track
+	if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+      	else validInfo->setGeneration(1);     // assume parent is a primary track
         ch2->setUserInformation(validInfo);
       }
       children[ichild] = ch2;
@@ -348,13 +348,13 @@ ISF::ISFParticleVector iFatras::PhotonConversionTool::getChilds(const ISF::ISFPa
 						  pdg1,
 						  time,
 						  *parent );
-    if (m_validationMode) {
-      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
-      validInfo->setProcess(14);
-      if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
-      else validInfo->setGeneration(1);     // assume parent is a primary track
-      ch1->setUserInformation(validInfo);
-    }
+    //if (m_validationMode) {
+    //  ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+    //  validInfo->setProcess(14);
+    //  if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+    //  else validInfo->setGeneration(1);     // assume parent is a primary track
+    //  ch1->setUserInformation(validInfo);
+    //}
     children[0] = ch1;
 
     ISF::ISFParticle* ch2  = new ISF::ISFParticle( vertex,
@@ -365,28 +365,28 @@ ISF::ISFParticleVector iFatras::PhotonConversionTool::getChilds(const ISF::ISFPa
 						   time,
 						   *parent );
       
-    if (m_validationMode) {
-      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
-      validInfo->setProcess(14);
-      if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
-      else validInfo->setGeneration(1);     // assume parent is a primary track
-      ch2->setUserInformation(validInfo);
-    }
+    //if (m_validationMode) {
+    //  ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+    //  validInfo->setProcess(14);
+    //  if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+    //  else validInfo->setGeneration(1);     // assume parent is a primary track
+    //  ch2->setUserInformation(validInfo);
+    //}
     children[1] = ch2;
 
     // register TruthIncident
-    ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(*parent),
-                                 children,
-                                 m_processCode,
-                                 parent->nextGeoID(),
-                                 ISF::fKillsPrimary );
-    m_truthRecordSvc->registerTruthIncident( truth);
+    //ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(*parent),
+    //                             children,
+    //                             m_processCode,
+    //                             parent->nextGeoID(),
+    //                             ISF::fKillsPrimary );
+    //m_truthRecordSvc->registerTruthIncident( truth);
 
     // save info for validation
-    if (m_validationMode && m_validationTool) {
-      Amg::Vector3D* nPrim=0;
-      m_validationTool->saveISFVertexInfo(14,vertex,*parent,parent->momentum(),nPrim,children);
-    }
+    //if (m_validationMode && m_validationTool) {
+    //  Amg::Vector3D* nPrim=0;
+    //  m_validationTool->saveISFVertexInfo(14,vertex,*parent,parent->momentum(),nPrim,children);
+    //}
 
     return children;
 }
@@ -599,7 +599,7 @@ Amg::Vector3D iFatras::PhotonConversionTool::childDirection(const Amg::Vector3D&
 
 }
 
-bool iFatras::PhotonConversionTool::doConversion(double time, const Trk::TrackParameters& parm,
+bool iFatras::PhotonConversionTool::doConversion(double time, const Trk::NeutralParameters& parm,
 						const Trk::ExtendedMaterialProperties* /*extMatProp*/) const {
   double p = parm.momentum().mag();
   
@@ -627,7 +627,7 @@ bool iFatras::PhotonConversionTool::doConversion(double time, const Trk::TrackPa
 
 /** interface for processing of the presampled nuclear interactions on layer*/
 ISF::ISFParticleVector iFatras::PhotonConversionTool::doConversionOnLayer(const ISF::ISFParticle* parent, 
-									 double time, const Trk::TrackParameters& parm,
+									 double time, const Trk::NeutralParameters& parm,
 									 const Trk::ExtendedMaterialProperties* /*ematprop*/) const {
   double p = parm.momentum().mag();
 
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhysicsValidationTool.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhysicsValidationTool.cxx
index d253484d56785ff407d46b13c81ac3f97bb1701d..14db928181f1e399cb43680cffce6818365793d9 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhysicsValidationTool.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/PhysicsValidationTool.cxx
@@ -76,6 +76,10 @@ iFatras::PhysicsValidationTool::initialize()
     m_particles->Branch("pph"       , &m_pph     , "pph/F"            );
     m_particles->Branch("p"         , &m_p      , "p/F"            );
     m_particles->Branch("eloss"     , &m_eloss  , "eloss/F"            );
+    m_particles->Branch("ionloss"     , &m_ionloss  , "ionloss/F"            );
+    m_particles->Branch("radloss"     , &m_radloss  , "radloss/F"            );
+    m_particles->Branch("zOaTr"     , &m_zOaTr  , "zOaTr/F"            );
+    m_particles->Branch("wZ"         , &m_wZ  ,   "wZ/F"            );
     m_particles->Branch("X0"        , &m_X0     , "X0/F"            );
     m_particles->Branch("dt"        , &m_dt     , "dt/F"            );
     m_particles->Branch("thIn"      , &m_thIn   , "thIn/F"            );
@@ -130,6 +134,83 @@ StatusCode iFatras::PhysicsValidationTool::finalize()
  *  ==> see headerfile
  *=======================================================================*/
 
+/** new transport tool */
+void iFatras::PhysicsValidationTool::saveISFParticleInfo(const ISF::ISFParticle& isp, 
+							 const Trk::ExtrapolationCell<Trk::TrackParameters>& ec,
+							 Trk::ExtrapolationCode ecode) {
+
+  m_p     = isp.momentum().mag();
+  m_ionloss = ec.eLoss ? ec.eLoss->meanIoni() : 0.;
+  m_radloss = ec.eLoss ? ec.eLoss->meanRad() : 0.;           // average estimate
+  m_zOaTr   = ec.zOaTrX;
+  m_wZ   = ec.zX;
+
+  if (ecode == Trk::ExtrapolationCode::SuccessBoundaryReached) {   // surviving particle
+    m_scEnd = 0;
+    m_eloss = ec.endParameters->momentum().mag()-m_p;
+    //m_dt = time - isp.timeStamp();
+    m_dt = ec.pathLength/CLHEP::c_light;   // TODO get timing info from the cell 
+
+    m_thEnd = ec.endParameters->position().theta();
+    m_phEnd = ec.endParameters->position().phi();
+    m_dEnd  = ec.endParameters->position().mag();
+
+  } else {
+
+    m_scEnd = -1;   // undefined
+    if (ecode == Trk::ExtrapolationCode::SuccessPathLimit) m_scEnd = 201;   // decay
+    else if (ecode == Trk::ExtrapolationCode::SuccessMaterialLimit ) m_scEnd = ec.materialProcess;   // material interaction
+
+    m_eloss = -m_p;
+    m_thEnd = -10.;     // TODO : retrieve position of stopped particle
+    m_phEnd = -10.;     // TODO : retrieve position of stopped particle 
+    m_dEnd = -1.;       // TODO : retrieve position of stopped particle
+  }
+  m_X0 = ec.materialX0;
+
+  saveInfo(isp);
+
+}
+
+/** new transport tool */
+void iFatras::PhysicsValidationTool::saveISFParticleInfo(const ISF::ISFParticle& isp, 
+							 const Trk::ExtrapolationCell<Trk::NeutralParameters>& ec,
+							 Trk::ExtrapolationCode ecode) {
+
+  m_p     = isp.momentum().mag();
+  m_ionloss = 0.;
+  m_radloss = 0.;
+  m_zOaTr   = ec.zOaTrX;
+  m_wZ   = ec.zX;
+
+  if (ecode == Trk::ExtrapolationCode::SuccessBoundaryReached) {   // surviving particle
+    m_scEnd = 0;
+    m_eloss = ec.endParameters->momentum().mag()-m_p;
+    //m_dt = time - isp.timeStamp();
+    m_dt = ec.pathLength/CLHEP::c_light;   // TODO get timing info from the cell 
+
+    m_thEnd = ec.endParameters->position().theta();
+    m_phEnd = ec.endParameters->position().phi();
+    m_dEnd  = ec.endParameters->position().mag();
+
+  } else {
+
+    m_scEnd = -1;   // undefined
+    if (ecode == Trk::ExtrapolationCode::SuccessPathLimit) m_scEnd = 201;   // decay
+    else if (ecode == Trk::ExtrapolationCode::SuccessMaterialLimit ) m_scEnd = ec.materialProcess;   // material interaction
+
+    m_eloss = -m_p;
+    m_thEnd = -10.;     // TODO : retrieve position of stopped particle
+    m_phEnd = -10.;     // TODO : retrieve position of stopped particle 
+    m_dEnd = -1.;       // TODO : retrieve position of stopped particle
+  }
+  m_X0 = ec.materialX0;
+
+  saveInfo(isp);
+
+}
+
+/** old transport tool/prompt decay */
 void iFatras::PhysicsValidationTool::saveISFParticleInfo(const ISF::ISFParticle& isp, 
 							 int endProcess,
 							 const Trk::TrackParameters* ePar,
@@ -137,17 +218,22 @@ void iFatras::PhysicsValidationTool::saveISFParticleInfo(const ISF::ISFParticle&
 
   m_pdg = isp.pdgCode();
   m_scIn = isp.getUserInformation()? isp.getUserInformation()->process() : 0;      // assume primary track
-  m_scEnd = endProcess;
   m_gen = isp.getUserInformation()? isp.getUserInformation()->generation() : 0;    // assume primary track 
   m_pth=isp.momentum().theta();
   m_pph=isp.momentum().phi();
-  m_p  =isp.momentum().mag();
   m_geoID = isp.nextGeoID();
-  m_eloss = ePar? ePar->momentum().mag()-m_p : -m_p;
-  m_dt = time - isp.timeStamp();
   m_dIn  = isp.position().mag();
   m_thIn = isp.position().theta();
   m_phIn = isp.position().phi();
+  m_p     = isp.momentum().mag();
+  m_scEnd = endProcess;
+  m_eloss = ePar? ePar->momentum().mag()-m_p : -m_p;
+  m_dt = time - isp.timeStamp();
+
+  m_ionloss = 0.;    // n.a.
+  m_radloss = 0.;    // n.a.
+  m_zOaTr   = 0.;    // n.a.
+
   if (ePar) { 
 
     //error propagation
@@ -163,6 +249,25 @@ void iFatras::PhysicsValidationTool::saveISFParticleInfo(const ISF::ISFParticle&
     m_dEnd = -1.;       // particle stopped and position unknown
   }
   m_X0 = dX0;
+
+  m_particles->Fill();
+
+}
+
+void iFatras::PhysicsValidationTool::saveInfo(const ISF::ISFParticle& isp) { 
+
+  // ISF particle info ( common )
+
+  m_pdg = isp.pdgCode();
+  m_scIn = isp.getUserInformation()? isp.getUserInformation()->process() : 0;      // assume primary track
+  m_gen = isp.getUserInformation()? isp.getUserInformation()->generation() : 0;    // assume primary track 
+  m_pth=isp.momentum().theta();
+  m_pph=isp.momentum().phi();
+  m_geoID = isp.nextGeoID();
+  m_dIn  = isp.position().mag();
+  m_thIn = isp.position().theta();
+  m_phIn = isp.position().phi();
+
   m_particles->Fill();
 
 }
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/ProcessSamplingTool.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/ProcessSamplingTool.cxx
index b3fceeab2e09b743b90821c29ebd22713e034741..8830505feb3e79687607aa33029de4c4070e16a4 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/ProcessSamplingTool.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/ProcessSamplingTool.cxx
@@ -13,6 +13,14 @@
 #include "TrkParameters/TrackParameters.h"
 // ISF includes
 #include "ISF_Event/ISFParticle.h"
+#include "ISF_Event/ITruthIncident.h"
+#include "ISF_Event/ISFTruthIncident.h"
+#include "ISF_Interfaces/ITruthSvc.h"
+// iFatras
+#include "ISF_FatrasInterfaces/IHadronicInteractionProcessor.h"
+#include "ISF_FatrasInterfaces/IPhysicsValidationTool.h"
+#include "ISF_FatrasInterfaces/IPhotonConversionTool.h"
+#include "ISF_FatrasInterfaces/IParticleDecayHelper.h"
 // CLHEP
 #include "CLHEP/Units/SystemOfUnits.h"
 #include "CLHEP/Random/RandFlat.h"
@@ -28,13 +36,29 @@ iFatras::ProcessSamplingTool::ProcessSamplingTool( const std::string& t,
                                       const std::string& n,
                                       const IInterface*  p )
   : AthAlgTool(t,n,p),
-   m_rndGenSvc("AtDSFMTGenSvc", n),
-   m_randomEngine(0),
-   m_randomEngineName("FatrasRnd")
+    m_rndGenSvc("AtDSFMTGenSvc", n),
+    m_randomEngine(0),
+    m_randomEngineName("FatrasRnd"),
+    m_truthRecordSvc("ISF_ValidationTruthService", n),
+    m_hadInt(true),
+    m_hadIntProcessor("iFatras::G4HadIntProcessor/FatrasG4HadIntProcessor"),
+    m_particleDecayer(),
+    m_conversionTool("iFatras::McConversionCreator/FatrasConversionCreator"),
+    m_validationMode(false),
+    m_validationTool("")
 {
   declareInterface<IProcessSamplingTool>(this);
   // service handles
-  declareProperty( "RandomNumberService",       m_rndGenSvc                );
+  declareProperty( "RandomNumberService"                , m_rndGenSvc                );
+  // hadronic interactions
+  declareProperty( "HadronicInteraction"                , m_hadInt);
+  declareProperty( "HadronicInteractionProcessor"       , m_hadIntProcessor);
+  declareProperty( "ParticleDecayHelper"                , m_particleDecayer      );
+  declareProperty( "PhotonConversionTool"               , m_conversionTool);
+  // validation mode ------------------------------------------------------------
+  declareProperty("ValidationMode"                      , m_validationMode);
+  declareProperty("PhysicsValidationTool"               , m_validationTool);
+  declareProperty("TruthRecordSvc"                      , m_truthRecordSvc        , "ISF Particle Truth Svc");      
 }
 
 /*=========================================================================
@@ -65,6 +89,43 @@ iFatras::ProcessSamplingTool::initialize()
     return StatusCode::FAILURE;
   }
 
+  if (m_truthRecordSvc.retrieve().isFailure()){
+    ATH_MSG_FATAL( "Could not retrieve " << m_truthRecordSvc );
+    return StatusCode::FAILURE;
+  }
+
+  // retrieve the photon conversion tool
+  if (m_conversionTool.retrieve().isFailure()){
+    ATH_MSG_FATAL( "Could not retrieve " << m_conversionTool );
+    return StatusCode::FAILURE;
+  } else
+    ATH_MSG_VERBOSE( "Successfully retrieved " << m_conversionTool );
+  
+  // retrieve the hadronic interaction tool
+  if (m_hadInt) {
+    if (m_hadIntProcessor.retrieve().isFailure()){
+      ATH_MSG_FATAL( "Could not retrieve " << m_hadIntProcessor );
+      return StatusCode::FAILURE;
+    } else
+      ATH_MSG_VERBOSE( "Successfully retrieved " << m_hadIntProcessor );                
+  }
+
+  // Particle decayer
+  if (m_particleDecayer.retrieve().isFailure()){
+    ATH_MSG_FATAL( "Could not retrieve " << m_particleDecayer );
+    return StatusCode::FAILURE;
+  } else
+    ATH_MSG_VERBOSE( "Successfully retrieved " << m_particleDecayer );                
+   
+  // retrieve the physics validation tool
+  if (m_validationMode) {
+    if (m_validationTool.retrieve().isFailure()){
+      ATH_MSG_FATAL( "Could not retrieve " << m_validationTool );
+      return StatusCode::FAILURE;
+    } else
+      ATH_MSG_VERBOSE( "Successfully retrieved " << m_validationTool );
+  }  
+
   return StatusCode::SUCCESS;
 }
 
@@ -78,7 +139,7 @@ StatusCode iFatras::ProcessSamplingTool::finalize()
   return StatusCode::SUCCESS;
 }
 
-Trk::PathLimit iFatras::ProcessSamplingTool::sampleProcess(double momentum,double charge,Trk::ParticleHypothesis particle) 
+Trk::PathLimit iFatras::ProcessSamplingTool::sampleProcess(double momentum,double charge,Trk::ParticleHypothesis particle) const
 {
   int process=0;
   double x0Max = -1.;
@@ -144,28 +205,189 @@ Trk::PathLimit iFatras::ProcessSamplingTool::sampleProcess(double momentum,doubl
   }
 
   // presumably here we are left with hadrons only
+  if (m_hadInt) {
+
+    // sample free path in terms of nuclear interaction length
+    double al = 1.;          // scaling here 
+    
+    /*
+      
+      if ( particle == Trk::pion || particle == Trk::kaon || particle == Trk::pi0 || particle == Trk::k0) {
+      al *= 1./(1.+ exp(-0.5*(momentum-270.)*(momentum-270.)/60./60.));
+      }
+      if ( particle == Trk::proton || particle == Trk::neutron ) al *=0.7;
+      if ( particle == Trk::pion || particle == Trk::pi0) al *=0.9;
+    */
+  
+    x0Max = -log(rndx)*al ;
+    
+    process = 121;
+
+    //std::cout <<"hadronic path limit:"<<momentum<<","<<al<<","<< x0Max << std::endl;
+    return Trk::PathLimit(x0Max,process);
+  }  
+
+
+  return Trk::PathLimit(x0Max,process);
+    
+  // return Trk::PathLimit(x0Max,process);
+}
+
+
+ISF::ISFParticleVector  iFatras::ProcessSamplingTool::interact(const ISF::ISFParticle* parent,
+							       Trk::ExCellCharged& eCell,
+							       const Trk::Material* mat) const
+{
+  ISF::ISFParticleVector childVector(0);
+  
+  int process = eCell.materialProcess;
+  if ( process==0 ) return childVector;
+
+  Trk::ParticleHypothesis particle = eCell.pHypothesis;
+  const Trk::TrackParameters* parm=eCell.leadParameters;
+    
+  double mass = m_particleMasses.mass[particle];
+  double p = parm->momentum().mag();
+  //double E = sqrt( p*p + mass*mass);
+  Amg::Vector3D position=parm->position();
+  Amg::Vector3D momentum=parm->momentum();
+  
+  if ( process == 5 ) {     // positron annihilation
+
+    double fmin = mass/p; 
+     
+    double fr = 1.-pow(fmin,CLHEP::RandFlat::shoot(m_randomEngine));
+
+    // double cTh = 1.-fmin/(1.-fr)/fr;
 
-  // sample free path in terms of nuclear interaction length
-  double al = 1.;          // scaling here 
+    // first implementation: ctH=1 
 
-  /*
+    ISF::ISFParticle* child1 = new ISF::ISFParticle( position,
+                                        fr*momentum,
+                                        0.,
+                                        0.,
+                                        22,
+                                        eCell.time,
+                                        *parent );
 
-  if ( particle == Trk::pion || particle == Trk::kaon || particle == Trk::pi0 || particle == Trk::k0) {
-    al *= 1./(1.+ exp(-0.5*(momentum-270.)*(momentum-270.)/60./60.));
+    ISF::ISFParticle* child2 = new ISF::ISFParticle( position,
+                                        (1-fr)*momentum,
+                                        0.,
+                                        0.,
+                                        22,
+                                        eCell.time,
+                                        *parent );
+
+    childVector.push_back(child1);     
+    childVector.push_back(child2);     
+
+  } else if (process==121) {    // hadronic interaction
+
+    //const Amg::Vector3D pDir = momentum.unit();
+
+    // const Trk::CurvilinearParameters parm(position,momentum,parent->charge());
+
+    childVector = m_hadIntProcessor->doHadIntOnLayer(parent, eCell.time, position, momentum, mat, particle);
+
+  } else if ( process == 201 ) {    // decay  
+    childVector = m_particleDecayer->decayParticle(*parent, position, momentum, eCell.time);
+  }
+
+  // validation mode 
+  if (m_validationMode) {
+
+    // add process info for children
+    for (unsigned int i=0; i<childVector.size(); i++) {
+      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      validInfo->setProcess(process);
+      if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+      else validInfo->setGeneration(1);     // assume parent is a primary track
+      childVector[i]->setUserInformation(validInfo);
+    }
+    // save interaction info 
+    if ( m_validationTool ) {
+      Amg::Vector3D* nMom = 0;
+      m_validationTool->saveISFVertexInfo(process, position,*parent,momentum,nMom,childVector);
+      delete nMom;
+    }
   }
-  if ( particle == Trk::proton || particle == Trk::neutron ) al *=0.7;
-  if ( particle == Trk::pion || particle == Trk::pi0) al *=0.9;
-  */
   
-  x0Max = -log(rndx)*al ;
+  // register TruthIncident
+  ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(*parent),
+			       childVector,
+			       process,
+			       parent->nextGeoID(),  // inherits from the parent
+			       ISF::fKillsPrimary );
+  m_truthRecordSvc->registerTruthIncident( truth);
+
+  //  
+  return childVector;
+}
+
+ISF::ISFParticleVector  iFatras::ProcessSamplingTool::interact(const ISF::ISFParticle* parent,
+							       Trk::ExCellNeutral& eCell,
+							       const Trk::Material* mat) const
+{
+  ISF::ISFParticleVector childVector(0);
+  
+  int process = eCell.materialProcess;
+  Trk::ParticleHypothesis particle = eCell.pHypothesis;
+  const Trk::NeutralParameters* parm=eCell.leadParameters;
+  
+  if ( process==0 ) return childVector;
+  //double mass = m_particleMasses.mass[particle];
+  //double p = parm.momentum().mag();
+  /*double E = sqrt( p*p + mass*mass);*/
+  Amg::Vector3D position=parm->position();
+  Amg::Vector3D momentum=parm->momentum();
 
-  process = 121;
+  if (process==14) {  // photon conversion   
 
-  //std::cout <<"hadronic path limit:"<<momentum<<","<<al<<","<< x0Max << std::endl;
+    childVector = m_conversionTool->doConversionOnLayer(parent, eCell.time, *parm); 
+
+  } else if (process==121) {    // hadronic interaction
+
+    //const Amg::Vector3D pDir = momentum.unit();
+
+    //const Trk::CurvilinearParameters parm(position,momentum,parent->charge());
+
+    childVector =  m_hadIntProcessor->doHadIntOnLayer(parent, eCell.time, position, momentum, mat, particle);
+
+  } else  if ( process == 201 ) {    // decay  
+
+    childVector = m_particleDecayer->decayParticle(*parent, position, momentum, eCell.time);
+  }
+
+  // validation mode 
+  if (m_validationMode) {
+
+    // add process info for children
+    for (unsigned int i=0; i<childVector.size(); i++) {
+      ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+      validInfo->setProcess(process);
+      if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
+      else validInfo->setGeneration(1);     // assume parent is a primary track
+      childVector[i]->setUserInformation(validInfo);
+    }
+    // save interaction info 
+    if ( m_validationTool ) {
+      Amg::Vector3D* nMom = 0;
+      m_validationTool->saveISFVertexInfo(process, position,*parent,momentum,nMom,childVector);
+      delete nMom;
+    }
+  }
+  
+  // register TruthIncident
+  ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(*parent),
+			       childVector,
+			       process,
+			       parent->nextGeoID(),  // inherits from the parent
+			       ISF::fKillsPrimary );
+  m_truthRecordSvc->registerTruthIncident( truth);
+
+  //
+  return childVector; 
   
-  return Trk::PathLimit(x0Max,process);
-    
-  // return Trk::PathLimit(x0Max,process);
 }
 
 
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportEngine.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportEngine.cxx
index 1eeb264c0b025e2ea49f6c71f342a465f9fdcbbb..14ff7365b71b313f2237d4f0601f93bb2f5043be 100644
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportEngine.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportEngine.cxx
@@ -14,12 +14,16 @@
 #include "TrkParameters/TrackParameters.h"
 #include "TrkNeutralParameters/NeutralParameters.h"
 #include "TrkExInterfaces/IExtrapolationEngine.h"
+#include "TrkExInterfaces/ITimedExtrapolator.h"
+
 #include "TrkGeometry/Layer.h"
+#include "TrkGeometry/TrackingVolume.h"
 
 // iFatras includes
 #include "ISF_FatrasInterfaces/ISimHitCreator.h"
 #include "ISF_FatrasInterfaces/IParticleDecayHelper.h"
 #include "ISF_FatrasInterfaces/IProcessSamplingTool.h"
+#include "ISF_FatrasInterfaces/IPhysicsValidationTool.h"
 
 // ISF includes
 #include "ISF_Event/ISFParticle.h"
@@ -30,6 +34,9 @@
 #include "CLHEP/Units/SystemOfUnits.h"
 #include "CLHEP/Random/RandFlat.h"
 
+// AtlasDetDescr
+#include "AtlasDetDescr/AtlasRegion.h"
+
 #include <iostream>
 
 //#include "AtlasDetDescr/AtlasDetectorID.h"
@@ -50,10 +57,15 @@ iFatras::TransportEngine::TransportEngine( const std::string& t,
     m_trackFilter(""),
     m_neutralHadronFilter(""),
     m_photonFilter(""),
-    m_samplingTool("")
+    m_samplingTool(""),
+    m_validationMode(false),
+    m_validationTool("")
 {
-  declareInterface<ITransportTool>(this);
+  declareInterface<ISF::IParticleProcessor>(this);
 
+  // validation output section
+  declareProperty( "ValidationMode",  m_validationMode );
+  declareProperty( "PhysicsValidationTool",     m_validationTool  );
   // tool handle for the particle decayer
   declareProperty( "ParticleDecayHelper",       m_particleDecayHelper      );  
   // tool handle for the track creator                                      
@@ -64,7 +76,7 @@ iFatras::TransportEngine::TransportEngine( const std::string& t,
   declareProperty( "TrackFilter",               m_trackFilter              );
   declareProperty( "NeutralFilter",             m_neutralHadronFilter      );
   declareProperty( "PhotonFilter",              m_photonFilter             );  
-  //
+  // tools handles ISF Framework
   declareProperty( "ProcessSamplingTool",       m_samplingTool             );
   // service handles
   declareProperty( "RandomNumberService",       m_rndGenSvc                );
@@ -102,6 +114,8 @@ iFatras::TransportEngine::initialize()
     return StatusCode::FAILURE;
   if (retrieveTool<iFatras::IProcessSamplingTool>(m_samplingTool).isFailure())
     return StatusCode::FAILURE;
+  if (m_validationMode && retrieveTool<iFatras::IPhysicsValidationTool>(m_validationTool).isFailure())
+      return StatusCode::FAILURE;
 
   if ( m_rndGenSvc.retrieve().isFailure() ){
     ATH_MSG_FATAL( "Could not retrieve " << m_rndGenSvc );
@@ -136,8 +150,8 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
   // copy the current particle onto the particle clipboard
   ISF::ParticleClipboard::getInstance().setParticle(isp);
   
-  ATH_MSG_INFO ("[ fatras transport ] processing particle " << isp.pdgCode() );
-  
+  ATH_MSG_DEBUG ("[ fatras transport ] processing particle " << isp.pdgCode() );
+
   // [0] ============================================================================================
   //  - INPUT PARTICLE PREPARATION
   //
@@ -174,13 +188,14 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
     ATH_MSG_VERBOSE( "[ fatras transport ] Determined processor w/o filter.");
   
   // now transport the particle - if it passes the filter
-  if ( filter && !filter->passFilter(isp) ) {
-    ATH_MSG_DEBUG( "[ fatras transport ] Filter not passed, ignore particle.");
-    ATH_MSG_DEBUG( "   -> for more information, turn on debug/verbose output of  " << filter->name() );
-    return 0;
-  }
+  //if ( filter && !filter->passFilter(isp) ) {
+  //  ATH_MSG_DEBUG( "[ fatras transport ] Filter not passed, ignore particle.");
+  //  ATH_MSG_DEBUG( "   -> for more information, turn on debug/verbose output of  " << filter->name() );
+  //  return 0;
+  //}
   
-  ATH_MSG_INFO( "[ fatras transport ] The StackParticle passed filter - starting transport.");
+  //ATH_MSG_DEBUG( "[ fatras transport ] The StackParticle passed filter - starting transport.");
+  ATH_MSG_DEBUG( "[ fatras transport ] starting transport.");
   
   // [a] DECAY section ------------------------------------------------------------------------------
   //
@@ -192,7 +207,13 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
   if ( pathLimit > 0. && pathLimit < 0.01 ) {
     if (!m_particleDecayHelper.empty()) {
       ATH_MSG_VERBOSE( "[ fatras transport ] Decay is triggered for input particle.");
-      m_particleDecayHelper->decay(isp);
+      m_particleDecayHelper->decay(isp,isp.position(),isp.momentum(),isp.timeStamp());
+    }
+
+    // validation mode - for all particle registered into stack
+    if ( m_validationMode && m_validationTool ) {
+      Trk::CurvilinearParameters inputPar(isp.position(),isp.momentum(),isp.charge());
+      m_validationTool->saveISFParticleInfo(isp,201,&inputPar,isp.timeStamp(),0.); 
     }
     return 0;
   }
@@ -202,20 +223,24 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
   //
   double materialLimitX0 = -1.;
   double materialLimitL0 = -1.;
-  // now sample the path limit with the path sampling tool
-  // -> the outcome is a material path limit
-  Trk::PathLimit matLim(-1.,0);
-  if (absPdg!=999 && pHypothesis<99) {
-      // sample the material process
-      matLim = m_samplingTool->sampleProcess(isp.momentum().mag(),isp.charge(),pHypothesis);
-      // now assign the limit to L0 or X0 (121 is the code used inside the sampling tool)
-      if (matLim.process == 121 ){
-          materialLimitL0 = matLim.x0Max;
-      } else 
-          materialLimitX0 = matLim.x0Max;
-      ATH_MSG_VERBOSE( "[ fatras transport ] Particle free path : " << matLim.x0Max << " and process : " << matLim.process);
+  int materialProcess = -1;
+  double materialX0=0.;
+  double materialL0=0.;
+  // now sample the path limit if not done already
+  ISF::MaterialPathInfo* matLimit = isp.getUserInformation() ? isp.getUserInformation()->materialLimit() : 0;
+  if (matLimit) {
+    materialProcess = matLimit->process;
+    if (materialProcess==121) materialLimitL0 = matLimit->dMax;
+    else  materialLimitX0 = matLimit->dMax;
+    if (materialProcess==121) materialL0=matLimit->dCollected;
+    else materialX0 = matLimit->dCollected;
+  } else if (absPdg!=999 && pHypothesis<99) { // need to resample   
+    Trk::PathLimit matLim = m_samplingTool->sampleProcess(isp.momentum().mag(),isp.charge(),pHypothesis);  
+    materialProcess = matLim.process;
+    if (materialProcess==121) materialLimitL0 = matLim.x0Max;
+    else  materialLimitX0 = matLim.x0Max;        
   }
-      
+  
   // [1] ============================================================================================  
   //  - TRANSPORT THROUGH THE DETECTOR
   //
@@ -237,9 +262,20 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
                                                                                   pathLimit,
                                                                                   materialLimitX0,
                                                                                   materialLimitL0);
-    ecc.materialProcess = matLim.process;
+    ecc.materialProcess = materialProcess;
+    if (ecc.materialLimitL0 != -1)
+      ecc.materialL0 = materialL0;
+      ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitL0);   
+    if (ecc.materialLimitX0 != -1)
+      ecc.materialX0 = materialX0;
+      ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
+
     // do the transport using the new engine 
-    Trk::ExtrapolationCode eCode =  m_extrapolationEngine->extrapolate(ecc);	
+    Trk::ExtrapolationCode eCode =  m_extrapolationEngine->extrapolate(ecc);
+ 
+    // validation info
+    if (m_validationMode ) m_validationTool->saveISFParticleInfo(isp,ecc,eCode); 
+	
     // resolve the different success states
     if (eCode.isSuccess()) {
       // this is a success - let's find out which one
@@ -249,11 +285,20 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
                                             eCode,
                                             ecc.endParameters->position(),
                                             ecc.endParameters->momentum(),
-                                            ecc.endParameters->charge(),
-                                            ecc.endParameters->position().mag()/CLHEP::c_light); //!< TODO update with pathLength
+					    ecc.pathLength/CLHEP::c_light,
+					    ecc.nextGeometrySignature);
       // memory cleanup  
-      delete ecc.endParameters;
+      // delete ecc.endParameters;
       // no hit creation -> return can be done now
+      if (rParticle && m_validationMode) {
+	// save validation info
+	ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+	validInfo->setProcess(0);
+	if (isp.getUserInformation()) validInfo->setGeneration(isp.getUserInformation()->generation());
+	else validInfo->setGeneration(0);     // assume primary parent
+	rParticle->setUserInformation(validInfo);
+      }
+
       return rParticle;
     } else {
       ATH_MSG_WARNING( "Error code " << eCode.toString() << " running the Extrapolator for neutral particle!" );
@@ -277,21 +322,32 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
                                                                                 materialLimitX0,
                                                                                 materialLimitL0);
     ecc.addConfigurationMode(Trk::ExtrapolationMode::CollectSensitive);
-    ecc.materialProcess = matLim.process;
+    ecc.materialProcess = materialProcess;
+    if (ecc.materialLimitL0 != -1)
+      ecc.materialL0 = materialL0;
+     ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitL0);
+    if (ecc.materialLimitX0 != -1)
+      ecc.materialX0 = materialX0;
+      ecc.addConfigurationMode(Trk::ExtrapolationMode::StopWithMaterialLimitX0);
     // do the transport using the new engine 
     // [B - 1] extrapoalte
     Trk::ExtrapolationCode eCode =  m_extrapolationEngine->extrapolate(ecc);	
+
+    // validation info
+    if (m_validationMode ) m_validationTool->saveISFParticleInfo(isp,ecc,eCode); 
+
     // resolve the different success states
     if (eCode.isSuccess()) {
         // this is a success - let's find out which one
         ATH_MSG_VERBOSE( "[ fatras transport ] Successfully run extrapolation for charged particle.");
-        // either give a particle back (at boundary) or the sub tools took care of it
+
+	// either give a particle back (at boundary) or the sub tools took care of it
         rParticle = handleExtrapolationResult(isp,
                                               eCode,
                                               ecc.endParameters->position(),
                                               ecc.endParameters->momentum(),
-                                              ecc.endParameters->charge(),
-                                              ecc.endParameters->position().mag()/CLHEP::c_light); //!< TODO update with pathLength
+					      ecc.pathLength/CLHEP::c_light,
+					      ecc.nextGeometrySignature);
         // memory cleanup       
         delete ecc.endParameters;
     } else {
@@ -323,6 +379,16 @@ ISF::ISFParticle* iFatras::TransportEngine::process( const ISF::ISFParticle& isp
         }
      }
   }
+   
+  if (rParticle && m_validationMode) {
+    // save validation info
+    ISF::ParticleUserInformation* validInfo = new ISF::ParticleUserInformation();
+    validInfo->setProcess(0);
+    if (isp.getUserInformation()) validInfo->setGeneration(isp.getUserInformation()->generation());
+    else validInfo->setGeneration(0);     // assume primary parent
+    rParticle->setUserInformation(validInfo);
+  }
+
   // return what you have to the ISF 
   return rParticle;
 }
@@ -333,30 +399,34 @@ ISF::ISFParticle* iFatras::TransportEngine::handleExtrapolationResult(const ISF:
                                                                       Trk::ExtrapolationCode eCode,
                                                                       const Amg::Vector3D& position,
                                                                       const Amg::Vector3D& momentum,
-                                                                      double charge,
-                                                                      double stime)
+								      double stime,
+								      Trk::GeometrySignature nextGeoID)
 {
+
     // the return particle
     ISF::ISFParticle* rParticle = 0;
     // switch the extrapolation code returns
     if (eCode == Trk::ExtrapolationCode::SuccessBoundaryReached){
         ATH_MSG_VERBOSE( "[ fatras transport ] Successfully reached detector boundary with the particle -> return particle at boundary.");
         // create the updated particle at the end of processing step
+	AtlasDetDescr::AtlasRegion geoID=AtlasDetDescr::AtlasRegion(5);
+	if (nextGeoID<99) geoID = AtlasDetDescr::AtlasRegion(nextGeoID);	  
         rParticle = new ISF::ISFParticle(position,
                                          momentum,
                                          isp.mass(),
                                          isp.charge(),
-                                         stime+isp.timeStamp(),
                                          isp.pdgCode(),
+                                         stime+isp.timeStamp(),
                                          isp,
                                          isp.barcode());
+	rParticle->setNextGeoID(geoID);
     } else if (eCode == Trk::ExtrapolationCode::SuccessPathLimit){
         ATH_MSG_VERBOSE( "[ fatras transport ] Successfully reached path limit for the particle -> decay & return 0.");
         // call the decayer tool
-        m_particleDecayHelper->decay(isp);
+        m_particleDecayHelper->decay(isp,position,momentum,stime+isp.timeStamp());
     } else if (eCode == Trk::ExtrapolationCode::SuccessMaterialLimit )
         ATH_MSG_VERBOSE( "[ fatras transport ] Successfully reached material limit for the particle -> return 0.");
+
     return rParticle;
 }
       
-
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportTool.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportTool.cxx
index 46be49de12d7a554275be585d72e020f73b04b56..980323fadf6ff8e6c4c8ab789d31b20615f7310c 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportTool.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/TransportTool.cxx
@@ -62,7 +62,7 @@ iFatras::TransportTool::TransportTool( const std::string& t,
    m_errorPropagation(false),
    m_hitsOff(false)
 {
-  declareInterface<ITransportTool>(this);
+  declareInterface<ISF::IParticleProcessor>(this);
   
   // validation output section
   declareProperty( "ValidationOutput",  m_validationOutput );
@@ -108,7 +108,7 @@ iFatras::TransportTool::initialize()
   if (retrieveTool<iFatras::ISimHitCreator>(m_simHitCreatorID).isFailure())
       return StatusCode::FAILURE;
   if (retrieveTool<iFatras::ISimHitCreator>(m_simHitCreatorMS).isFailure())
-     return StatusCode::FAILURE;
+      return StatusCode::FAILURE;
   if (retrieveTool<Trk::ITimedExtrapolator>(m_extrapolator).isFailure()) 
       return StatusCode::FAILURE;
   if (retrieveTool<iFatras::IParticleDecayHelper>(m_particleDecayHelper).isFailure())
@@ -245,7 +245,7 @@ ISF::ISFParticle* iFatras::TransportTool::process( const ISF::ISFParticle& isp)
   if ( freepath>0. && freepath<0.01 ) {
     if (!m_particleDecayHelper.empty()) {
       ATH_MSG_VERBOSE( "[ fatras transport ] Decay is triggered for input particle.");
-      m_particleDecayHelper->decay(isp);
+      m_particleDecayHelper->decay(isp,isp.position(),isp.momentum(),isp.timeStamp());
     }
 
     // validation mode - for all particle registered into stack
@@ -257,9 +257,15 @@ ISF::ISFParticle* iFatras::TransportTool::process( const ISF::ISFParticle& isp)
     return 0;
   }
 
-  // presample interactions
+  // presample interactions if not done already
   Trk::PathLimit pathLim(-1.,0);
-  if (absPdg!=999 && pHypothesis<99) pathLim = m_samplingTool->sampleProcess(mom,isp.charge(),pHypothesis);
+  ISF::MaterialPathInfo* matLimit = isp.getUserInformation() ? isp.getUserInformation()->materialLimit() : 0;
+  if (matLimit) {
+    pathLim=Trk::PathLimit( matLimit->dMax,matLimit->process);
+    pathLim.updateMat(matLimit->dCollected,13.,0.);          // arbitrary Z choice : update MaterialPathInfo  
+  } else if (absPdg!=999 && pHypothesis<99) { // need to resample   
+    pathLim = m_samplingTool->sampleProcess(isp.momentum().mag(),isp.charge(),pHypothesis);  
+  }
      
   // use extrapolation with path limit - automatic exit at subdetector boundary
   // NB: don't delete eParameters, it's memory is managed inside the extrapolator
@@ -369,7 +375,7 @@ ISF::ISFParticle* iFatras::TransportTool::process( const ISF::ISFParticle& isp)
   if (uisp && timeLim.tMax>0.  && timeLim.time >=timeLim.tMax ) {
     if (!m_particleDecayHelper.empty()) {
       ATH_MSG_VERBOSE( "[ fatras transport ] Decay is triggered for input particle.");
-      m_particleDecayHelper->decay(*uisp);
+      m_particleDecayHelper->decay(*uisp,uisp->position(),uisp->momentum(),uisp->timeStamp());
     }
     delete uisp; 
     return 0;
diff --git a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/components/ISF_FatrasTools_entries.cxx b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/components/ISF_FatrasTools_entries.cxx
index 18734e63a1f14ba488c57259b62ca9d4b0dd912d..3f455cd6b4385c7b07355e5e0bf03aa050d21334 100755
--- a/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/components/ISF_FatrasTools_entries.cxx
+++ b/Simulation/ISF/ISF_Fatras/ISF_FatrasTools/src/components/ISF_FatrasTools_entries.cxx
@@ -5,19 +5,24 @@
 #include "ISF_FatrasTools/McMaterialEffectsEngine.h"
 #include "ISF_FatrasTools/HadIntProcessorParametric.h"
 #include "ISF_FatrasTools/McEnergyLossUpdator.h"
-#include "ISF_FatrasTools/McBetheHeitlerEnergyLossUpdator.h"
 #include "ISF_FatrasTools/PhotonConversionTool.h"
 #include "ISF_FatrasTools/ProcessSamplingTool.h"
 #include "ISF_FatrasTools/PhysicsValidationTool.h"
 
+#include "ISF_FatrasTools/MultipleScatteringSamplerHighland.h"
+#include "ISF_FatrasTools/MultipleScatteringSamplerGaussianMixture.h"
+#include "ISF_FatrasTools/MultipleScatteringSamplerGeneralMixture.h"
+
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , TransportTool )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , TransportEngine )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , McMaterialEffectsUpdator )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , McMaterialEffectsEngine )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , HadIntProcessorParametric )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , McEnergyLossUpdator )
-DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , McBetheHeitlerEnergyLossUpdator )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , PhotonConversionTool )
+DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , MultipleScatteringSamplerGaussianMixture )
+DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , MultipleScatteringSamplerGeneralMixture )
+DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , MultipleScatteringSamplerHighland )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , ProcessSamplingTool )
 DECLARE_NAMESPACE_TOOL_FACTORY( iFatras , PhysicsValidationTool )