diff --git a/DDG4/plugins/Geant4TVUserParticleHandler.cpp b/DDG4/plugins/Geant4TVUserParticleHandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..daf8c3402d23a06f34537b653ee90fc56a6c3dfa
--- /dev/null
+++ b/DDG4/plugins/Geant4TVUserParticleHandler.cpp
@@ -0,0 +1,167 @@
+//==========================================================================
+//  AIDA Detector description implementation
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+/** \addtogroup Geant4Action
+ *
+ @{
+   \package Geant4TCUserParticleHandler
+ * \brief Rejects to keep particles, which are created outside a tracking cylinder.
+ *
+ *
+@}
+ */
+
+#ifndef DD4HEP_DDG4_GEANT4TCUSERPARTICLEHANDLER_H
+#define DD4HEP_DDG4_GEANT4TCUSERPARTICLEHANDLER_H
+
+// Framework include files
+#include <DD4hep/Primitives.h>
+#include <DDG4/Geant4UserParticleHandler.h>
+
+/// Namespace for the AIDA detector description toolkit
+namespace dd4hep {
+
+  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
+  namespace sim {
+
+    ///  Rejects to keep particles, which are created outside a tracking cylinder.
+    /** Geant4TCUserParticleHandler
+     *
+     *  TC stands for TrackingCylinder ;-)
+     *
+     * @author  M.Frank
+     * @version 1.0
+     */
+    class Geant4TCUserParticleHandler : public Geant4UserParticleHandler  {
+      double m_zTrackerMin, m_zTrackerMax, m_rTracker;
+    public:
+      /// Standard constructor
+      Geant4TCUserParticleHandler(Geant4Context* context, const std::string& nam);
+
+      /// Default destructor
+      virtual ~Geant4TCUserParticleHandler() {}
+
+      /// Post-track action callback
+      /** Allow the user to force the particle handling in the post track action
+       *  set the reason mask to NULL in order to drop the particle.
+       *  The parent's reasoning mask will be or'ed with the particle's mask
+       *  to preserve the MC truth for the hit creation.
+       *  The default implementation is empty.
+       *
+       *  Note: The particle passed is a temporary and will be copied if kept.
+       */
+      virtual void end(const G4Track* track, Particle& particle);
+
+      /// Post-event action callback: avoid warning (...) was hidden [-Woverloaded-virtual]
+      virtual void end(const G4Event* event);
+
+    };
+  }    // End namespace sim
+}      // End namespace dd4hep
+
+#endif // DD4HEP_DDG4_GEANT4TCUSERPARTICLEHANDLER_H
+
+//====================================================================
+//  AIDA Detector description implementation
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+// Framework include files
+//#include <DDG4/Geant4TCUserParticleHandler.h>
+#include <DDG4/Geant4Particle.h>
+#include <DDG4/Factories.h>
+
+
+using namespace dd4hep::sim;
+DECLARE_GEANT4ACTION(Geant4TCUserParticleHandler)
+
+/// Standard constructor
+Geant4TCUserParticleHandler::Geant4TCUserParticleHandler(Geant4Context* ctxt, const std::string& nam)
+: Geant4UserParticleHandler(ctxt,nam)
+{
+  declareProperty("TrackingVolume_Zmin",m_zTrackerMin=-1e100);
+  declareProperty("TrackingVolume_Zmax",m_zTrackerMax=1e100);
+  declareProperty("TrackingVolume_Rmax",m_rTracker=1e100);
+}
+
+/// Post-track action callback
+void Geant4TCUserParticleHandler::end(const G4Track* /* track */, Particle& p)  {
+
+  double r_prod = std::sqrt(p.vsx*p.vsx + p.vsy*p.vsy);
+  double z_prod = p.vsz;
+  bool starts_in_trk_vol = ( r_prod <= m_rTracker
+    && z_prod >= (m_zTrackerMin == -1e100? -m_zTrackerMax : m_zTrackerMin)
+    && z_prod <= m_zTrackerMax
+  )  ;
+
+  dd4hep::detail::ReferenceBitMask<int> reason(p.reason);
+
+  if( reason.isSet(G4PARTICLE_PRIMARY) ) {
+    //do nothing
+  } else if( starts_in_trk_vol && ! reason.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD) )  {
+    // created in tracking volume but below energy cut
+    p.reason = 0;
+    return;
+  }
+
+  double r_end  = std::sqrt(p.vex*p.vex + p.vey*p.vey);
+  double z_end  = p.vez;
+  bool ends_in_trk_vol =  ( r_end <= m_rTracker
+     && z_end >= (m_zTrackerMin == -1e100? -m_zTrackerMax : m_zTrackerMin)
+     && z_end <= m_zTrackerMax
+  ) ;
+
+  // created and ended in calo but not primary particle
+  //
+  // we can have particles from the generator only in the calo, if we have a
+  // long particle with preassigned decay, we need to keep the reason or the
+  // MChistory will not be updated later on
+  if( not reason.isSet(G4PARTICLE_PRIMARY) ) {
+    if( !starts_in_trk_vol ) {
+      if( !ends_in_trk_vol ){
+	p.reason = 0;
+      }
+      //fg: dont keep backscatter that did not create a tracker hit
+      else if( ! reason.isSet(G4PARTICLE_CREATED_TRACKER_HIT) ) {
+	p.reason = 0;
+      }
+    }
+  }
+
+  // Set the simulator status bits
+  dd4hep::detail::ReferenceBitMask<int> simStatus(p.status);
+
+  if( ends_in_trk_vol ) {
+    simStatus.set(G4PARTICLE_SIM_DECAY_TRACKER);
+  }
+
+  // if the particle doesn't end in the tracker volume it must have ended in the calorimeter
+  if( not ends_in_trk_vol && not simStatus.isSet(G4PARTICLE_SIM_LEFT_DETECTOR) ) {
+    simStatus.set(G4PARTICLE_SIM_DECAY_CALO);
+  }
+
+  if( not starts_in_trk_vol && ends_in_trk_vol ) {
+    simStatus.set(G4PARTICLE_SIM_BACKSCATTER);
+  }
+
+  return ;
+
+}
+
+/// Post-event action callback
+void Geant4TCUserParticleHandler::end(const G4Event* /* event */)   {
+
+}
+