diff --git a/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt b/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt
index 85f315959c231816328750723e2675d424540968..787d91a405fae0ea19c643fe22fd9098247e0f48 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt
+++ b/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt
@@ -18,26 +18,29 @@ atlas_depends_on_subdirs( PUBLIC
                           Generators/GeneratorObjects
                           InnerDetector/InDetSimEvent
                           MuonSpectrometer/MuonSimEvent
+                          Simulation/Barcode/BarcodeEvent
                           Simulation/Barcode/BarcodeInterfaces
-                          Simulation/Barcode/BarcodeServices
                           Simulation/G4Atlas/G4AtlasInterfaces
                           Simulation/G4Sim/SimHelpers
                           Simulation/G4Sim/TrackRecord
                           Simulation/ISF/ISF_Core/ISF_Event
                           Simulation/ISF/ISF_Core/ISF_Interfaces
+                          Simulation/ISF/ISF_HepMC/ISF_HepMC_Interfaces
                           TileCalorimeter/TileSimEvent
                           Tools/PmbCxxUtils )
 
 # External dependencies:
+find_package( CLHEP )
 find_package( HepMC )
+find_package( HepPDT )
 find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
 
 # Component(s) in the package:
 atlas_add_component( ISF_Services
                      src/*.cxx
                      src/components/*.cxx
-                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${HEPMC_LIBRARIES} GaudiKernel CaloIdentifier CaloSimEvent AthenaBaseComps StoreGateLib SGtests AtlasDetDescr GeneratorObjects InDetSimEvent MuonSimEvent BarcodeServicesLib G4AtlasInterfaces SimHelpers ISF_Event ISF_Interfaces TileSimEvent PmbCxxUtils )
+                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${HEPMC_LIBRARIES} ${CLHEP_LIBRARIES} ${HEPPDT_LIBRARIES} GaudiKernel CaloIdentifier CaloSimEvent AthenaBaseComps StoreGateLib SGtests AtlasDetDescr GeneratorObjects InDetSimEvent MuonSimEvent G4AtlasInterfaces SimHelpers ISF_Event ISF_Interfaces TileSimEvent PmbCxxUtils )
 
 # Install files from the package:
 atlas_install_headers( ISF_Services )
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements b/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements
index a2e7b8a9026613f8e8b4c7012ffb182873c43e23..51a24f0e619dc69ddbf767a65f7af1c6f61cd5fb 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements
+++ b/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements
@@ -13,17 +13,20 @@ use AthenaBaseComps               AthenaBaseComps-*       Control
 use AtlasDetDescr                 AtlasDetDescr-*         DetectorDescription
 use AtlasHepMC                    AtlasHepMC-*            External
 use AtlasROOT                     AtlasROOT-*             External
+use BarcodeEvent                  BarcodeEvent-*          Simulation/Barcode
 use BarcodeInterfaces             BarcodeInterfaces-*     Simulation/Barcode
-use BarcodeServices               BarcodeServices-*        Simulation/Barcode
 use GeneratorObjects              GeneratorObjects-*      Generators
 use G4AtlasInterfaces             G4AtlasInterfaces-*     Simulation/G4Atlas
 use InDetSimEvent                 InDetSimEvent-*         InnerDetector
 use ISF_Interfaces                ISF_Interfaces-*        Simulation/ISF/ISF_Core
 use ISF_Event                     ISF_Event-*             Simulation/ISF/ISF_Core
+use ISF_HepMC_Interfaces          ISF_HepMC_Interfaces-*  Simulation/ISF/ISF_HepMC
 use MuonSimEvent                  MuonSimEvent-*          MuonSpectrometer
 use PmbCxxUtils                   PmbCxxUtils-*           Tools
 use StoreGate                     StoreGate-*             Control
 use SubDetectorEnvelopes          SubDetectorEnvelopes-*  AtlasGeometryCommon
+use HepPDT                        *                       LCG_Interfaces
+use AtlasCLHEP                    AtlasCLHEP-*            External
 end_private
 
 public
@@ -31,6 +34,26 @@ library ISF_Services *.cxx components/*.cxx
 apply_pattern declare_python_modules files="*.py"
 apply_pattern component_library
 
+# tests
+private
+pattern GTest_run \
+        application <unit_test>_test -group=$(whichGroup) ../test/<unit_test>_test.cxx <extra_sources> ; \
+        document athenarun_launcher <unit_test>_utest -group=$(whichGroup) \
+        athenarun_exe="'../${CMTCONFIG}/<unit_test>_test.exe'" \
+        athenarun_pre="'. ../cmt/setup.sh'" \
+        athenarun_out="' 2>&1 | tee <unit_test>_test.log'" \
+        athenarun_post="'../test/gtest_post_check.sh <unit_test>_test.log'" ; \
+        private ; \
+        macro_append <unit_test>_utest_dependencies " <unit_test>_test " ; \
+
+use AtlasGoogleTest      AtlasGoogleTest-*       External
+use TestTools            TestTools-*             AtlasTest
+use GeoPrimitives        GeoPrimitives-*         DetectorDescription
+apply_pattern GTest_run unit_test=InputConverter extra_sources=../src/InputConverter.cxx
+
+end_private
+
+
 private
 # use this to activate debug info in this package:
 #macro cppdebugflags '$(cppdebugflags_s)'
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py
index 61d8e07ce6bc992e2bdb13144fd1fdf06c1a37b0..e49026674487396f246f02f0764c4592a253a57e 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py
+++ b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py
@@ -11,67 +11,159 @@ from AthenaCommon.Constants import *  # FATAL,ERROR etc.
 from AthenaCommon.SystemOfUnits import *
 
 def getParticleBrokerSvcNoOrdering(name="ISF_ParticleBrokerSvcNoOrdering", **kwargs):
-    kwargs.setdefault('StackFiller'                 , 'ISF_StackFiller'                     )
-    kwargs.setdefault('EntryLayerTool'              , 'ISF_EntryLayerTool'                  )
-    kwargs.setdefault('GeoIDSvc'                    , 'ISF_GeoIDSvc'                        )
-    kwargs.setdefault('AlwaysUseGeoIDSvc'           , False                                 )
+    kwargs.setdefault('EntryLayerTool', 'ISF_EntryLayerTool')
+    kwargs.setdefault('GeoIDSvc', 'ISF_GeoIDSvc')
+    kwargs.setdefault('AlwaysUseGeoIDSvc', False)
     from ISF_Config.ISF_jobProperties import ISF_Flags
-    kwargs.setdefault('ValidateGeoIDs'              , ISF_Flags.ValidationMode()            )
-    kwargs.setdefault('ValidationOutput'            , ISF_Flags.ValidationMode()            )
-    kwargs.setdefault('ValidationStreamName'        , "ParticleBroker"                      )
-    kwargs.setdefault('BarcodeService'              , ISF_Flags.BarcodeService()            )
+    kwargs.setdefault('ValidateGeoIDs', ISF_Flags.ValidationMode())
+    kwargs.setdefault('ValidationOutput', ISF_Flags.ValidationMode())
+    kwargs.setdefault('ValidationStreamName', "ParticleBroker")
+    kwargs.setdefault('BarcodeService', ISF_Flags.BarcodeService())
     return CfgMgr.ISF__ParticleBrokerDynamicOnReadIn(name, **kwargs)
 
 def getParticleBrokerSvc(name="ISF_ParticleBrokerSvc", **kwargs):
-    #kwargs.setdefault('ParticleOrderingTool'       , 'ISF_InToOutSubDetOrderingTool'       )
-    kwargs.setdefault('ParticleOrderingTool'        , 'ISF_ParticleOrderingTool'            )
-    return getParticleBrokerSvcNoOrdering(name, **kwargs)
-
-def getLongLivedParticleBrokerSvc(name="ISF_LongLivedParticleBrokerSvc", **kwargs):
-    kwargs.setdefault('StackFiller'                 , 'ISF_LongLivedStackFiller'            )
+    #kwargs.setdefault('ParticleOrderingTool', 'ISF_InToOutSubDetOrderingTool')
+    kwargs.setdefault('ParticleOrderingTool', 'ISF_ParticleOrderingTool')
     return getParticleBrokerSvcNoOrdering(name, **kwargs)
 
 def getAFIIParticleBrokerSvc(name="ISF_AFIIParticleBrokerSvc", **kwargs):
-    kwargs.setdefault('EntryLayerTool'              , 'ISF_AFIIEntryLayerTool'              )
+    kwargs.setdefault('EntryLayerTool', 'ISF_AFIIEntryLayerTool')
     return getParticleBrokerSvc(name, **kwargs)
 
 def getSimHitService(name="ISF_SimHitService", **kwargs):
     from ISF_Config.ISF_jobProperties import ISF_Flags
-    kwargs.setdefault('ValidationOutput'    , ISF_Flags.ValidationMode()                    )
+    kwargs.setdefault('ValidationOutput', ISF_Flags.ValidationMode())
     return CfgMgr.ISF__SimHitSvc(name, **kwargs)
 
 def getNoG4SimHitService(name="ISF_NoG4SimHitService", **kwargs):
-    kwargs.setdefault("SensitiveDetectorMasterTool","EmptySensitiveDetectorMasterTool")
-    kwargs.setdefault("FastSimulationMasterTool"   ,"EmptyFastSimulationMasterTool"   )
+    kwargs.setdefault("SensitiveDetectorMasterTool", "EmptySensitiveDetectorMasterTool")
+    kwargs.setdefault("FastSimulationMasterTool", "EmptyFastSimulationMasterTool")
     return getSimHitService(name, **kwargs)
 
 def getPileupSimHitService(name="ISF_PileupSimHitService", **kwargs):
-    kwargs.setdefault('SeparateInDetPileupHits'    , True )
+    kwargs.setdefault('SeparateInDetPileupHits', True)
     return getNoG4SimHitService(name, **kwargs)
 
 def getISFEnvelopeDefSvc(name="ISF_ISFEnvelopeDefSvc", **kwargs):
     # ATLAS common envlope definitions
-    kwargs.setdefault("ATLASEnvelopeDefSvc"    , "AtlasGeometry_EnvelopeDefSvc")
+    kwargs.setdefault("ATLASEnvelopeDefSvc", "AtlasGeometry_EnvelopeDefSvc")
+    return CfgMgr.ISF__ISFEnvelopeDefSvc(name, **kwargs)
     return CfgMgr.ISF__ISFEnvelopeDefSvc(name, **kwargs)
 
 def getAFIIEnvelopeDefSvc(name="ISF_AFIIEnvelopeDefSvc", **kwargs):
     from AthenaCommon.SystemOfUnits import mm
     # ATLAS common envlope definitions
-    kwargs.setdefault("ISFEnvelopeDefSvc"    , "ISF_ISFEnvelopeDefSvc"         )
-    kwargs.setdefault("InDetMaxExtentZ"      , 3549.5*mm                       )
+    kwargs.setdefault("ISFEnvelopeDefSvc", "ISF_ISFEnvelopeDefSvc")
+    kwargs.setdefault("InDetMaxExtentZ", 3549.5*mm)
+    return CfgMgr.ISF__AFIIEnvelopeDefSvc(name, **kwargs)
     return CfgMgr.ISF__AFIIEnvelopeDefSvc(name, **kwargs)
 
 
 def getGeoIDSvc(name="ISF_GeoIDSvc", **kwargs):
     # with ISF volume definitions
-    kwargs.setdefault("EnvelopeDefSvc"          , "ISF_ISFEnvelopeDefSvc"      )
+    kwargs.setdefault("EnvelopeDefSvc", "ISF_ISFEnvelopeDefSvc")
+    return CfgMgr.ISF__GeoIDSvc(name, **kwargs)
     return CfgMgr.ISF__GeoIDSvc(name, **kwargs)
 
 
 def getAFIIGeoIDSvc(name="ISF_AFIIGeoIDSvc", **kwargs):
-    kwargs.setdefault("EnvelopeDefSvc"          , "ISF_AFIIEnvelopeDefSvc"     )
+    kwargs.setdefault("EnvelopeDefSvc", "ISF_AFIIEnvelopeDefSvc")
     return getGeoIDSvc(name, **kwargs)
 
 def getParticleKillerSvc(name="ISF_ParticleKillerSvc", **kwargs):
     kwargs.setdefault('Identifier',           "ParticleKiller")
     return CfgMgr.ISF__ParticleKillerSimSvc(name, **kwargs)
+
+def getInputConverter(name="ISF_InputConverter", **kwargs):
+    kwargs.setdefault("UseGeneratedParticleMass", False)
+    genParticleFilters = ['ISF_ParticleFinalStateFilter']
+    from AthenaCommon.BeamFlags import jobproperties
+    if jobproperties.Beam.beamType() != "cosmics":
+        genParticleFilters += ['ISF_ParticlePositionFilterDynamic',
+                                'ISF_EtaPhiFilter']
+    genParticleFilters += ['ISF_GenParticleInteractingFilter']
+    kwargs.setdefault("GenParticleFilters", genParticleFilters)
+    return CfgMgr.ISF__InputConverter(name, **kwargs)
+
+def getLongLivedInputConverter(name="ISF_LongLivedInputConverter", **kwargs):
+    kwargs.setdefault("GenParticleFilters"      , [ 'ISF_ParticleSimWhiteList',
+                                                    'ISF_ParticlePositionFilterDynamic',
+                                                    'ISF_EtaPhiFilter',
+                                                    'ISF_GenParticleInteractingFilter', ] )
+    return getInputConverter(name, **kwargs)
+
+def getGenericTruthService(name="ISF_TruthService", **kwargs):
+    from ISF_Config.ISF_jobProperties import ISF_Flags
+    kwargs.setdefault('BarcodeSvc', ISF_Flags.BarcodeService())
+    kwargs.setdefault('SkipIfNoChildren', True)
+    kwargs.setdefault('SkipIfNoParentBarcode', True)
+    kwargs.setdefault('ForceEndVtxInRegions', [])
+    if 'longLived' in ISF_Flags.Simulator(): #FIXME this should be configured in a nicer way. ATLASSIM-526
+        kwargs.setdefault('QuasiStableParticlesIncluded', True)
+    return CfgMgr.ISF__TruthSvc(name, **kwargs)
+
+def getMC15TruthService(name="ISF_MC15TruthService", **kwargs):
+    # importing Reflex dictionary to access AtlasDetDescr::AtlasRegion enum
+    import ROOT, cppyy
+    cppyy.loadDictionary('AtlasDetDescrDict')
+    AtlasRegion = ROOT.AtlasDetDescr
+    kwargs.setdefault('BeamPipeTruthStrategies', ['ISF_MCTruthStrategyGroupID_MC15']) # this is used for beam pipe but not BeamPipeCentral which uses same as ID
+    kwargs.setdefault('IDTruthStrategies', ['ISF_MCTruthStrategyGroupID_MC15', 'ISF_MCTruthStrategyGroupIDHadInt_MC15'])
+    kwargs.setdefault('CaloTruthStrategies', ['ISF_MCTruthStrategyGroupCaloMuBrem', 'ISF_MCTruthStrategyGroupCaloDecay_MC15'])
+    kwargs.setdefault('MSTruthStrategies', [])
+    kwargs.setdefault('IgnoreUndefinedBarcodes', False)
+    kwargs.setdefault('PassWholeVertices', False) # new for MC15 - can write out partial vertices.
+    kwargs.setdefault('ForceEndVtxInRegions', [AtlasRegion.fAtlasID])
+    return getGenericTruthService(name, **kwargs)
+
+def getMC15aTruthService(name="ISF_MC15aTruthService", **kwargs):
+    kwargs.setdefault('ForceEndVtxInRegions', [])
+    return getMC15TruthService(name, **kwargs)
+
+def getMC15aPlusTruthService(name="ISF_MC15aPlusTruthService", **kwargs):
+    # importing Reflex dictionary to access AtlasDetDescr::AtlasRegion enum
+    import ROOT, cppyy
+    cppyy.loadDictionary('AtlasDetDescrDict')
+    AtlasRegion = ROOT.AtlasDetDescr
+    kwargs.setdefault('ForceEndVtxInRegions', [AtlasRegion.fAtlasID])
+    return getMC15TruthService(name, **kwargs)
+
+def getMC12TruthService(name="ISF_MC12TruthService", **kwargs):
+    kwargs.setdefault('BeamPipeTruthStrategies', ['ISF_MCTruthStrategyGroupID']) # this is used for beam pipe but not BeamPipeCentral which uses same as ID
+    kwargs.setdefault('IDTruthStrategies', ['ISF_MCTruthStrategyGroupID', 'ISF_MCTruthStrategyGroupIDHadInt'])
+    kwargs.setdefault('CaloTruthStrategies', ['ISF_MCTruthStrategyGroupCaloMuBrem'])
+    kwargs.setdefault('MSTruthStrategies', [])
+    kwargs.setdefault('IgnoreUndefinedBarcodes', False)
+    kwargs.setdefault('PassWholeVertices', True)
+    return getGenericTruthService(name, **kwargs)
+
+def getMC12LLPTruthService(name="ISF_MC12TruthLLPService", **kwargs):
+    kwargs.setdefault('BeamPipeTruthStrategies', ['ISF_MCTruthStrategyGroupID', 'ISF_LLPTruthStrategy']) # this is used for beam pipe but not BeamPipeCentral which uses same as ID
+    kwargs.setdefault('IDTruthStrategies', ['ISF_MCTruthStrategyGroupID', 'ISF_MCTruthStrategyGroupIDHadInt', 'ISF_LLPTruthStrategy'])
+    kwargs.setdefault('CaloTruthStrategies', ['ISF_MCTruthStrategyGroupCaloMuBrem', 'ISF_LLPTruthStrategy'])
+    kwargs.setdefault('MSTruthStrategies', ['ISF_LLPTruthStrategy'])
+    return getMC12TruthService(name, **kwargs)
+
+def getMC12PlusTruthService(name="ISF_MC12PlusTruthService", **kwargs):
+    # importing Reflex dictionary to access AtlasDetDescr::AtlasRegion enum
+    import ROOT, cppyy
+    cppyy.loadDictionary('AtlasDetDescrDict')
+    AtlasRegion = ROOT.AtlasDetDescr
+    kwargs.setdefault('ForceEndVtxInRegions', [AtlasRegion.fAtlasID] )
+    return getMC12TruthService(name, **kwargs)
+
+def getValidationTruthService(name="ISF_ValidationTruthService", **kwargs):
+    kwargs.setdefault('BeamPipeTruthStrategies', [])
+    kwargs.setdefault('IDTruthStrategies', ['ISF_ValidationTruthStrategy'] )
+    kwargs.setdefault('CaloTruthStrategies', ['ISF_ValidationTruthStrategy'] )
+    kwargs.setdefault('MSTruthStrategies', [])
+    kwargs.setdefault('IgnoreUndefinedBarcodes', True)
+    kwargs.setdefault('PassWholeVertices', True)
+    return getGenericTruthService(name, **kwargs)
+
+def getTruthService(name="ISF_TruthService", **kwargs):
+    from ISF_Config.ISF_jobProperties import ISF_Flags
+    if ISF_Flags.ValidationMode() :
+      return getValidationTruthService(name, **kwargs)
+    else :
+      return getMC12TruthService(name, **kwargs)
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py
index 7e1a333128bbd7dcd11600f9301371f8fdc0f88d..3c60c7152e2b0ddc3ded276fd505358464e9ff2f 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py
+++ b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py
@@ -8,15 +8,24 @@ Elmar Ritsch, 16/12/2014
 from AthenaCommon.CfgGetter import addService
 
 # Common tools, services and algorithms used by jobs
-addService("ISF_Services.ISF_ServicesConfig.getISFEnvelopeDefSvc"           , "ISF_ISFEnvelopeDefSvc"               )
-addService("ISF_Services.ISF_ServicesConfig.getAFIIEnvelopeDefSvc"          , "ISF_AFIIEnvelopeDefSvc"              )
-addService("ISF_Services.ISF_ServicesConfig.getGeoIDSvc"                    , "ISF_GeoIDSvc"                        )
-addService("ISF_Services.ISF_ServicesConfig.getAFIIGeoIDSvc"                , "ISF_AFIIGeoIDSvc"                    )
-addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvc"           , "ISF_ParticleBrokerSvc"               )
-addService("ISF_Services.ISF_ServicesConfig.getLongLivedParticleBrokerSvc"  , "ISF_LongLivedParticleBrokerSvc"      )
-addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvcNoOrdering" , "ISF_ParticleBrokerSvcNoOrdering"     )
-addService("ISF_Services.ISF_ServicesConfig.getAFIIParticleBrokerSvc"       , "ISF_AFIIParticleBrokerSvc"           )
-addService("ISF_Services.ISF_ServicesConfig.getSimHitService"               , "ISF_SimHitService"                   )
-addService("ISF_Services.ISF_ServicesConfig.getNoG4SimHitService"           , "ISF_NoG4SimHitService"               )
-addService("ISF_Services.ISF_ServicesConfig.getPileupSimHitService"         , "ISF_PileupSimHitService"             )
-addService("ISF_Services.ISF_ServicesConfig.getParticleKillerSvc"           , "ISF_ParticleKillerSvc"               )
+addService("ISF_Services.ISF_ServicesConfig.getISFEnvelopeDefSvc", "ISF_ISFEnvelopeDefSvc")
+addService("ISF_Services.ISF_ServicesConfig.getAFIIEnvelopeDefSvc", "ISF_AFIIEnvelopeDefSvc")
+addService("ISF_Services.ISF_ServicesConfig.getGeoIDSvc", "ISF_GeoIDSvc")
+addService("ISF_Services.ISF_ServicesConfig.getAFIIGeoIDSvc", "ISF_AFIIGeoIDSvc")
+addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvc", "ISF_ParticleBrokerSvc")
+addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvcNoOrdering", "ISF_ParticleBrokerSvcNoOrdering")
+addService("ISF_Services.ISF_ServicesConfig.getAFIIParticleBrokerSvc", "ISF_AFIIParticleBrokerSvc")
+addService("ISF_Services.ISF_ServicesConfig.getSimHitService", "ISF_SimHitService")
+addService("ISF_Services.ISF_ServicesConfig.getNoG4SimHitService", "ISF_NoG4SimHitService")
+addService("ISF_Services.ISF_ServicesConfig.getPileupSimHitService", "ISF_PileupSimHitService")
+addService("ISF_Services.ISF_ServicesConfig.getInputConverter", "ISF_InputConverter")
+addService("ISF_Services.ISF_ServicesConfig.getLongLivedInputConverter", "ISF_LongLivedInputConverter")
+addService("ISF_Services.ISF_ServicesConfig.getTruthService", "ISF_TruthService")
+addService("ISF_Services.ISF_ServicesConfig.getMC12TruthService", "ISF_MC12TruthService")
+addService("ISF_Services.ISF_ServicesConfig.getMC12PlusTruthService", "ISF_MC12PlusTruthService")
+addService("ISF_Services.ISF_ServicesConfig.getMC12LLPTruthService", "ISF_MC12LLPTruthService")
+addService("ISF_Services.ISF_ServicesConfig.getMC15aTruthService", "ISF_MC15aTruthService")
+addService("ISF_Services.ISF_ServicesConfig.getMC15aPlusTruthService", "ISF_MC15aPlusTruthService")
+addService("ISF_Services.ISF_ServicesConfig.getMC15TruthService", "ISF_MC15TruthService")
+addService("ISF_Services.ISF_ServicesConfig.getValidationTruthService", "ISF_ValidationTruthService")
+addService("ISF_Services.ISF_ServicesConfig.getParticleKillerSvc", "ISF_ParticleKillerSvc")
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7e712640ddf90f1713e38a0a0956cac7db1927c5
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.cxx
@@ -0,0 +1,296 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// InputConverter.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+// class header include
+#include "InputConverter.h"
+
+// framework
+#include "GaudiKernel/IPartPropSvc.h"
+#include "GaudiKernel/PhysicalConstants.h"
+
+// ISF_HepMC include
+#include "ISF_Event/TruthBinding.h"
+#include "ISF_HepMC_Interfaces/IGenParticleFilter.h"
+// barcode event and interfaces for bc creation
+#include "BarcodeEvent/Barcode.h"
+#include "BarcodeInterfaces/IBarcodeSvc.h"
+// ISF_Event include
+#include "ISF_Event/ISFParticle.h"
+#include "ISF_Event/ISFParticleContainer.h"
+#include "ISF_Event/ParticleUserInformation.h"
+// HepMC includes
+#include "HepMC/GenParticle.h"
+#include "HepMC/GenEvent.h"
+// McEventCollection
+#include "GeneratorObjects/McEventCollection.h"
+// CLHEP includes
+#include "CLHEP/Geometry/Point3D.h"
+#include "CLHEP/Geometry/Vector3D.h"
+// HepPDT
+#include "HepPDT/ParticleID.hh"
+#include "HepPDT/DecayData.hh"
+#include "HepPDT/ParticleDataTable.hh"
+
+
+/** Constructor **/
+ISF::InputConverter::InputConverter(const std::string& name, ISvcLocator* svc)
+    : AthService(name,svc),
+      m_particlePropSvc("PartPropSvc",name),
+      m_particleDataTable(nullptr),
+      m_useGeneratedParticleMass(false),
+      m_genParticleFilters()
+{
+  // particle mass from particle data table?
+  declareProperty("UseGeneratedParticleMass",
+                  m_useGeneratedParticleMass,
+                  "Use particle mass assigned to GenParticle.");
+  // particle filters
+  declareProperty("GenParticleFilters",
+                  m_genParticleFilters,
+                  "Tools for filtering out GenParticles.");
+  // the particle property service
+  declareProperty("ParticlePropertyService",
+                  m_particlePropSvc,
+                  "ParticlePropertyService to retrieve the PDT.");
+}
+
+
+/** Destructor **/
+ISF::InputConverter::~InputConverter()
+{
+}
+
+
+// Athena algtool's Hooks
+StatusCode
+ISF::InputConverter::initialize()
+{
+  ATH_MSG_VERBOSE("initialize() begin");
+
+  // setup PDT if requested (to get particle masses later on)
+  if (!m_useGeneratedParticleMass) {
+    ATH_CHECK( m_particlePropSvc.retrieve() );
+    m_particleDataTable = m_particlePropSvc->PDT();
+    if (!m_particleDataTable) {
+      ATH_MSG_FATAL( "Could not get ParticleDataTable from " << m_particlePropSvc << ". Abort" );
+      return StatusCode::FAILURE;
+    }
+  }
+
+  if (!m_genParticleFilters.empty()){
+    ATH_CHECK(m_genParticleFilters.retrieve());
+  }
+
+  ATH_MSG_VERBOSE("initialize() successful");
+  return StatusCode::SUCCESS;
+}
+
+
+/** Athena algtool Hook */
+StatusCode
+ISF::InputConverter::finalize()
+{
+  ATH_MSG_DEBUG("Finalizing ...");
+  return StatusCode::SUCCESS;
+}
+
+
+/** Convert selected particles from the given McEventCollection into ISFParticles
+    and push them into the given ISFParticleContainer */
+StatusCode
+ISF::InputConverter::convert(const McEventCollection& inputGenEvents,
+                             ISF::ISFParticleContainer& simParticles,
+                             bool isPileup) const
+{
+  for ( const auto& eventPtr : inputGenEvents ) {
+    // skip empty events
+    if (eventPtr == nullptr) continue;
+
+    // @FIXME: set the bunch-crossing identifier for pileup dynamically
+    // rather than a constant '1' (e.g. could use GenEvent index for that?)
+    int bcid = isPileup ? 1 : 0;
+
+    ATH_MSG_DEBUG("Starting conversion of GenEvent with"
+                  " signal_process_id=" << eventPtr->signal_process_id() <<
+                  " and event_number=" << eventPtr->event_number() );
+
+    // new collection containing all gen particles that passed filters
+    bool legacyOrdering = true; // FIXME: this is only to keep the same order of particles
+                                //        as the prior 'StackFiller' implementation
+                                // TODO:  remove this functionality from the
+                                //        getSelectedParticles function once
+                                //        happy with the results
+    const auto passedGenParticles = getSelectedParticles(*eventPtr, legacyOrdering);
+
+    for ( auto& genPartPtr : passedGenParticles ) {
+      ATH_MSG_VERBOSE("Picking up following GenParticle for conversion to ISFParticle: " <<  *genPartPtr);
+      auto simParticlePtr = convertParticle(genPartPtr, bcid);
+      if (!simParticlePtr) {
+        ATH_MSG_ERROR("Error while trying to convert input generator particles. Aborting.");
+        return StatusCode::FAILURE;
+      }
+      // add to collection that will be returned
+      simParticles.push_back(simParticlePtr);
+
+    } // loop over passed gen particles
+
+  } // loop over gen events
+
+  ATH_MSG_DEBUG( "Created initial simulation particle collection with size " << simParticles.size() );
+
+  return StatusCode::SUCCESS;
+}
+
+
+/** get all generator particles which pass filters */
+std::vector<HepMC::GenParticle*>
+ISF::InputConverter::getSelectedParticles(const HepMC::GenEvent& evnt, bool legacyOrdering) const {
+  auto allGenPartBegin = evnt.particles_begin();
+  auto allGenPartEnd = evnt.particles_end();
+
+  // reserve destination container with maximum size, i.e. number of particles in input event
+  std::vector<HepMC::GenParticle*> passedGenParticles{};
+  size_t maxParticles = std::distance(allGenPartBegin, allGenPartEnd);
+  passedGenParticles.reserve(maxParticles);
+
+  if (legacyOrdering) {
+    // FIXME: remove this block and the 'legacyOrdering' flag
+    //        once we don't need the legacy order any longer
+    auto vtxIt = evnt.vertices_begin();
+    auto vtxItEnd = evnt.vertices_end();
+    for ( ; vtxIt != vtxItEnd; ++vtxIt ) {
+      const auto vtxPtr = *vtxIt;
+      std::copy_if(vtxPtr->particles_begin(HepMC::children),
+                   vtxPtr->particles_end(HepMC::children),
+                   std::back_inserter(passedGenParticles),
+                   [this](HepMC::GenParticle* p){return this->passesFilters(*p);});
+    }
+
+  } else {
+    std::copy_if(allGenPartBegin,
+                 allGenPartEnd,
+                 std::back_inserter(passedGenParticles),
+                 [this](HepMC::GenParticle* p){return this->passesFilters(*p);});
+  }
+
+  passedGenParticles.shrink_to_fit();
+
+  return passedGenParticles;
+}
+
+
+/** get all generator particles which pass filters */
+ISF::ISFParticle*
+ISF::InputConverter::convertParticle(HepMC::GenParticle* genPartPtr, int bcid) const {
+
+  if (!genPartPtr)
+      return nullptr;
+
+  auto& genPart = *genPartPtr;
+
+  // -> particle origin (TODO: add proper GeoID, collision/cosmics)
+  DetRegionSvcIDPair origin(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID);
+
+  // -> truth binding
+  ISF::TruthBinding* tBinding = new ISF::TruthBinding(genPartPtr);
+
+  // 4-vectors: position, momentum
+  HepMC::GenVertex* pVertex = genPart.production_vertex();
+  if (!pVertex) {
+    ATH_MSG_ERROR("Unable to convert following generator particle due to missing "
+                  << "production vertex: " << genPart);
+    return nullptr;
+  }
+  const auto& pVertexPos(pVertex->point3d());
+  const Amg::Vector3D pos(pVertexPos.x(), pVertexPos.y(), pVertexPos.z());
+  const auto& pMomentum(genPart.momentum());
+  const Amg::Vector3D mom(pMomentum.px(), pMomentum.py(), pMomentum.pz());
+
+  // get the pdg_id, mass & time, barcode
+  int pPdgId = genPart.pdg_id();
+  double pMass = getParticleMass(genPart);
+  double pTime = pVertex->position().t() / Gaudi::Units::c_light;
+  double charge = HepPDT::ParticleID(pPdgId).charge();
+  auto pBarcode = genPart.barcode();
+
+  auto sParticle = new ISF::ISFParticle( std::move(pos),
+                                         std::move(mom),
+                                         pMass,
+                                         charge,
+                                         pPdgId,
+                                         pTime,
+                                         origin,
+                                         bcid,
+                                         pBarcode,
+                                         tBinding );
+  return sParticle;
+}
+
+
+/** get right GenParticle mass */
+double
+ISF::InputConverter::getParticleMass(const HepMC::GenParticle &part) const {
+  // default value: generated particle mass
+  double mass = part.generated_mass();
+  ATH_MSG_VERBOSE("part.generated_mass, mass="<<mass);
+
+  // 1. use PDT mass?
+  if ( !m_useGeneratedParticleMass) {
+    int absPDG = abs(part.pdg_id());
+    HepPDT::ParticleData const *pData = (m_particleDataTable)
+      ? m_particleDataTable->particle(absPDG)
+      : nullptr ;
+    if (pData) {
+      mass = pData->mass();
+      ATH_MSG_VERBOSE("using pData mass, mass="<<mass);
+    }
+    else
+      ATH_MSG_WARNING( "Unable to find mass of particle with PDG ID '" << absPDG << "' in ParticleDataTable. Will set mass to generated_mass: " << mass);
+  }
+  return mass;
+}
+
+
+/** check if the given particle passes all filters */
+bool
+ISF::InputConverter::passesFilters(const HepMC::GenParticle& part) const {
+  // TODO: implement this as a std::find_if with a lambda function
+  for ( const auto& filter : m_genParticleFilters ) {
+    // determine if the particle passes current filter
+    bool passFilter = filter->pass(part);
+    ATH_MSG_VERBOSE("GenParticleFilter '" << filter.typeAndName() << "' returned: "
+                    << (passFilter ? "true, will keep particle."
+                        : "false, will remove particle."));
+    const auto& momentum = part.momentum();
+    ATH_MSG_VERBOSE("Particle: ("
+                    <<momentum.px()<<", "
+                    <<momentum.py()<<", "
+                    <<momentum.pz()<<"), pdgCode: "
+                    <<part.pdg_id() );
+
+    if (!passFilter) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+/** Query the interfaces. */
+StatusCode ISF::InputConverter::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+
+  if ( IID_IInputConverter == riid )
+    *ppvInterface = (IInputConverter*)this;
+  else  {
+    // Interface is not directly available: try out a base class
+    return Service::queryInterface(riid, ppvInterface);
+  }
+  addRef();
+  return StatusCode::SUCCESS;
+}
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.h b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa3449343f59383fa3d9e222b6cecb8e826336eb
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.h
@@ -0,0 +1,100 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// InputConverter.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef ISF_INPUTCONVERTER_H
+#define ISF_INPUTCONVERTER_H 1
+
+// STL includes
+#include <string>
+// ISF include
+#include "ISF_Interfaces/IInputConverter.h"
+// FrameWork includes
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "AthenaBaseComps/AthService.h"
+
+// forward declarations
+namespace Barcode {
+  class IBarcodeSvc;
+}
+namespace HepPDT {
+  class ParticleDataTable;
+}
+namespace HepMC {
+  class GenParticle;
+  class GenEvent;
+}
+class IPartPropSvc;
+class McEventCollection;
+namespace ISFTesting {
+  class InputConverter_test;
+}
+namespace ISF {
+  class ISFParticle;
+  class IGenParticleFilter;
+}
+
+namespace ISF {
+
+  /** @class InputConverter
+
+      Convert simulation input collections to ISFParticles for subsequent ISF simulation.
+
+      @author Elmar.Ritsch -at- cern.ch
+     */
+  class InputConverter : public IInputConverter, public AthService {
+
+    // allow test to access private data
+    friend ISFTesting::InputConverter_test;
+
+    public:
+      InputConverter(const std::string& name, ISvcLocator* svc);
+      virtual ~InputConverter();
+
+      /** Athena algtool Hooks */
+      StatusCode  initialize();
+      StatusCode  finalize();
+
+      /** ReturnGaudi InterfaceID */
+      static const InterfaceID& interfaceID() { return IID_IInputConverter; }
+
+      /** Convert selected particles from the given McEventCollection into ISFParticles
+          and push them into the given ISFParticleContainer */
+      virtual StatusCode convert(const McEventCollection& inputGenEvents,
+                                 ISF::ISFParticleContainer& simParticles,
+                                 bool isPileup=false) const override final;
+
+      /** Query the interfaces. **/
+      StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface );
+
+    private:
+      /** get right GenParticle mass */
+      double getParticleMass(const HepMC::GenParticle& p) const;
+
+      /** get all generator particles which pass filters */
+      std::vector<HepMC::GenParticle*> getSelectedParticles(const HepMC::GenEvent& evnt, bool legacyOrdering=false) const;
+
+      /** check if the given particle passes all filters */
+      bool passesFilters(const HepMC::GenParticle& p) const;
+
+      /** convert GenParticle to ISFParticle */
+      ISF::ISFParticle* convertParticle(HepMC::GenParticle* genPartPtr, int bcid) const;
+
+      /** ParticlePropertyService and ParticleDataTable */
+      ServiceHandle<IPartPropSvc>           m_particlePropSvc;          //!< particle properties svc to retrieve PDT
+      const HepPDT::ParticleDataTable      *m_particleDataTable;        //!< PDT used to look up particle masses
+
+      bool                                  m_useGeneratedParticleMass; //!< use GenParticle::generated_mass() in simulation
+
+      ToolHandleArray<IGenParticleFilter>   m_genParticleFilters;       //!< HepMC::GenParticle filters
+  };
+
+}
+
+
+#endif //> !ISF_INPUTCONVERTER_H
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx
index be743f021e4e17f3bea2c84f57b556f6e4016e12..360cc86b52915c0ea60488e386dc6ef9e9af0111 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx
@@ -14,7 +14,6 @@
 #include "ISF_Event/ISFParticleContainer.h"
 #include "ISF_Event/ISFBenchmarkHelper.h"
 
-#include "ISF_Interfaces/IStackFiller.h"
 #include "ISF_Interfaces/IEntryLayerTool.h"
 #include "ISF_Interfaces/IGeoIDSvc.h"
 #include "ISF_Interfaces/SimulationFlavor.h"
@@ -22,9 +21,6 @@
 // DetectorDescription
 #include "AtlasDetDescr/AtlasRegionHelper.h"
 
-// barcode utils
-#include "BarcodeServices/BitCalculator.h"
-
 // Benchmarking
 #include "PmbCxxUtils/CustomBenchmark.h"
 
@@ -40,11 +36,9 @@
 /** Constructor **/
 ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::string& name,ISvcLocator* svc) :
   AthService(name,svc),
-  m_particleStackFiller("ISF::ISF_GenEventStackFiller/StackFiller"),
   m_entryLayerTool("iGeant4::EntryLayerTool/ISF_EntryLayerTool"),
-  m_entryLayerToolQuick(0),
   m_orderingTool(""),
-  m_orderingToolQuick(0),
+  m_hasOrderingTool(false),
   m_geoIDSvc("", name),
   m_geoIDSvcQuick(0),
   m_forceGeoIDSvc(false),
@@ -54,7 +48,6 @@ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::str
   m_simSelector(),
   m_simSelectorSet(),
   m_screenOutputPrefix("isf >> "),
-  m_screenEmptyPrefix(),
   m_barcodeSvc("", name),
   m_doSelectorCPUMon(false),
   m_benchPDGCode(0),
@@ -68,11 +61,8 @@ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::str
   m_val_p(0.),
   m_val_x(0.),
   m_val_y(0.),
-  m_val_z(0.),
-  m_simflavor(ISF::UndefinedSim)
+  m_val_z(0.)
 {
-  // the particle stack filler tool
-  declareProperty("StackFiller"                , m_particleStackFiller  );
   // the entry layer tool to write TrackRecordCollections
   declareProperty("EntryLayerTool"             , m_entryLayerTool       );
   // particle ing tool
@@ -83,8 +73,6 @@ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::str
   declareProperty("ValidateGeoIDs"             , m_validateGeoID        );
   // collect and print cpu monitoring information
   declareProperty("SimSelectorCPUMonitoring"   , m_doSelectorCPUMon     );
-  // refine the screen output for debugging
-  declareProperty("ScreenOutputPrefix"         , m_screenOutputPrefix   );
   // The Particle/Vertex BarcodeService used in ISF to store barcode info
   declareProperty("BarcodeService"             , m_barcodeSvc,
                   "The Particle/Vertex BarcodeService used in ISF" );
@@ -109,46 +97,33 @@ ISF::ParticleBrokerDynamicOnReadIn::~ParticleBrokerDynamicOnReadIn()
 /** framework methods */
 StatusCode ISF::ParticleBrokerDynamicOnReadIn::initialize()
 {
-
-  // Screen output
-  for (size_t prl = 0; prl < m_screenOutputPrefix.size(); ++prl) m_screenEmptyPrefix += " ";
-  ATH_MSG_DEBUG ( m_screenOutputPrefix << "--------------------------------------------------------");
-
-  // retrieve the particle stack filler tool
-  if ( m_particleStackFiller.retrieve().isFailure() ){
-    ATH_MSG_FATAL( m_screenOutputPrefix <<  "Could not retrieve ParticleStack Filler. Abort.");
-    return StatusCode::FAILURE;
-  } else
-    ATH_MSG_INFO( m_screenEmptyPrefix <<  "- StackFiller      : " << m_particleStackFiller.typeAndName() );
+  ATH_MSG_INFO("initialize() ...");
 
   // retrieve the entry layer tool
   if ( m_entryLayerTool.retrieve().isFailure() ){
-    ATH_MSG_FATAL( m_screenOutputPrefix <<  "Could not retrieve EntryLayer Tool. Abort.");
+    ATH_MSG_FATAL("Could not retrieve EntryLayer Tool. Abort.");
     return StatusCode::FAILURE;
   } else {
-    ATH_MSG_INFO( m_screenEmptyPrefix <<  "- EntryLayerTool   : " << m_entryLayerTool.typeAndName() );
-    // store a quick-access-pointer (removes GaudiOverhead)
-    m_entryLayerToolQuick = &(*m_entryLayerTool);
+    ATH_MSG_INFO( "- EntryLayerTool   : " << m_entryLayerTool.typeAndName() );
   }
 
   // retrieve the particle ing tool if given
   if ( ! m_orderingTool.empty()) {
     if ( m_orderingTool.retrieve().isFailure() ){
-      ATH_MSG_FATAL( m_screenOutputPrefix <<  "Could not retrieve ParticleOrderingTool. Abort.");
+      ATH_MSG_FATAL("Could not retrieve ParticleOrderingTool. Abort.");
       return StatusCode::FAILURE;
     } else {
-      ATH_MSG_INFO( m_screenEmptyPrefix <<  "- Particel OrderingTool   : " << m_orderingTool.typeAndName() );
-      // store a quick-access-pointer (removes GaudiOverhead)
-      m_orderingToolQuick = &(*m_orderingTool);
+      ATH_MSG_INFO( "- Particel OrderingTool   : " << m_orderingTool.typeAndName() );
+      m_hasOrderingTool = true;
     }
   }
 
   // retrieve the geo identification decision tool
   if ( m_geoIDSvc.retrieve().isFailure()){
-    ATH_MSG_FATAL( m_screenOutputPrefix << "Could not retrieve GeometryIdentifier Service. Abort.");
+    ATH_MSG_FATAL("Could not retrieve GeometryIdentifier Service. Abort.");
     return StatusCode::FAILURE;
   } else {
-    ATH_MSG_INFO( m_screenEmptyPrefix <<  "- GeoIDSvc         : "
+    ATH_MSG_INFO( "- GeoIDSvc         : "
                   << (m_geoIDSvc.empty() ? "<not configured>" : m_geoIDSvc.typeAndName()) );
     // store a quick-access-pointer (removes GaudiOverhead)
     m_geoIDSvcQuick = &(*m_geoIDSvc);
@@ -192,7 +167,7 @@ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initialize()
     // error when trying to retrieve the THistSvc
     else {
       // -> turn off validation output
-      ATH_MSG_ERROR( m_screenOutputPrefix << "Validation mode turned on but unable to retrieve THistService. Will not write out ROOT histograms/Trees.");
+      ATH_MSG_ERROR("Validation mode turned on but unable to retrieve THistService. Will not write out ROOT histograms/Trees.");
       m_validationOutput = false;
     }
 
@@ -206,7 +181,7 @@ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initialize()
 /** framework methods */
 StatusCode ISF::ParticleBrokerDynamicOnReadIn::finalize()
 {
-  ATH_MSG_INFO ( m_screenOutputPrefix << "finalize() successful");
+  ATH_MSG_INFO("finalize() ...");
   return StatusCode::SUCCESS;
 }
 
@@ -278,15 +253,9 @@ void ISF::ParticleBrokerDynamicOnReadIn::fillPosValTree( TTree *tree,
 
 /** update all SimulationSelectors in the routing chain with the given particle */
 void ISF::ParticleBrokerDynamicOnReadIn::updateAllSelectors(const ISFParticle &particle) {
-
-  // update all simSelectors with the given (new) particle
-
-  // iterators used to loop over all sim Selectors
-  SimSelectorSet::iterator  simSelectorIter    = m_simSelectorSet.begin();
-  SimSelectorSet::iterator  simSelectorIterEnd = m_simSelectorSet.end();
-
-  for ( ; simSelectorIter != simSelectorIterEnd; ++simSelectorIter)
-    (*simSelectorIter)->update( particle);
+  for ( const auto& simSelector : m_simSelectorSet ) {
+    simSelector->update(particle);
+  }
 }
 
 
@@ -307,14 +276,10 @@ void ISF::ParticleBrokerDynamicOnReadIn::selectAndStore( ISF::ISFParticle* p)
     // register the SimulatorID to the particle
     p->setNextSimID( selectedSimID);
 
-    // record the simulation flavor in the particle's extra barcode
-    storeSimulationFlavor( p );
-
-    // set particle order
-    if (m_orderingToolQuick) m_orderingToolQuick->setOrder( *p);
+    if (m_hasOrderingTool) m_orderingTool->setOrder(*p);
 
-    // push the particle onto the particle container
-    m_particles.push( p);
+    // store particle locally
+    m_particles.push(p);
 
     // no simulator could be found
     //   -> drop particle
@@ -333,19 +298,6 @@ void ISF::ParticleBrokerDynamicOnReadIn::selectAndStore( ISF::ISFParticle* p)
   }
 }
 
-
-/** store the simulation flavor of SimulationSelector that has selected the particle */
-void ISF::ParticleBrokerDynamicOnReadIn::storeSimulationFlavor( ISF::ISFParticle* p )
-{
-  // m_simflavor has been identified in identifySimID()
-  if ( m_barcodeSvc->hasBitCalculator() ) {
-    Barcode::ParticleBarcode extrabc = p->getExtraBC();
-    m_barcodeSvc->getBitCalculator()->SetSimulator(extrabc,m_simflavor);
-    p->setExtraBC( extrabc );
-  }
-}
-
-
 /** go through the chain of SimulationSelectors and return the SimulatoID of the first
     SimulationSelector that selects the particle */
 ISF::SimSvcID ISF::ParticleBrokerDynamicOnReadIn::identifySimID( const ISF::ISFParticle* p) {
@@ -382,39 +334,13 @@ ISF::SimSvcID ISF::ParticleBrokerDynamicOnReadIn::identifySimID( const ISF::ISFP
   // determine the simulator ID
   ISF::SimSvcID simID = selected ? (*--selectorIt)->simSvcID() : ISF::SimSvcID(ISF::fUndefinedSimID);
 
-  // reset simulation flavor -> stored in setSimulationFlavor();
-  m_simflavor = ISF::UndefinedSim;
-
-  if (selected) {
-    std::string simulatorType("none");
-    ServiceHandle<ISimulationSvc>* hsimulator = (*selectorIt)->simulator();
-    if ( hsimulator!=0 ) {
-      //if ( simulator.retrieve().isSuccess() ) {
-      //if ( (*(*--selectorIt)->simulator()) != 0 ) {
-      simulatorType = (*hsimulator).type();
-      //}
-    }
-    std::transform(simulatorType.begin(), simulatorType.end(), simulatorType.begin(), ::tolower);
-
-    if      (simulatorType.find("fatras")!=std::string::npos)   { m_simflavor = ISF::FatrasSim; }
-    else if (simulatorType.find("g4")!=std::string::npos)       { m_simflavor = ISF::Geant4Sim; }
-    else if (simulatorType.find("geant")!=std::string::npos)    { m_simflavor = ISF::Geant4Sim; }
-    else if (simulatorType.find("full")!=std::string::npos)     { m_simflavor = ISF::Geant4Sim; }
-    else if (simulatorType.find("fastcalo")!=std::string::npos) { m_simflavor = ISF::FastCaloSim; }
-    else    { m_simflavor = ISF::UndefinedSim; } // = 0
-
-    ATH_MSG_DEBUG( "simulation flavor : " << m_simflavor << " " << simulatorType );
-
-  }
-
   return simID;
 }
 
 
 /** Initialize the stackSvc and the truthSvc */
-StatusCode ISF::ParticleBrokerDynamicOnReadIn::initializeEvent()
+StatusCode ISF::ParticleBrokerDynamicOnReadIn::initializeEvent(ISFParticleContainer&& simParticles)
 {
-
   ATH_MSG_DEBUG( m_screenOutputPrefix << "Initializing particle stack");
 
   // fill set of simulation selectors once per job
@@ -431,61 +357,34 @@ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initializeEvent()
   }
 
   // call beginEvent() for all selectors registerd to the ParticleBroker:
-  //   iterators used to loop over all sim Selectors
-  SimSelectorSet::iterator  simSelectorIter    = m_simSelectorSet.begin();
-  SimSelectorSet::iterator  simSelectorIterEnd = m_simSelectorSet.end();
-  for ( ; simSelectorIter != simSelectorIterEnd; ++simSelectorIter)
-    (*simSelectorIter)->beginEvent(); // call beginEvent() on current selector
-
-  // read particles from EvGen
-  ISFParticleContainer initContainer;
-  if ( m_particleStackFiller->fillStack( initContainer).isFailure() ){
-    ATH_MSG_FATAL (  m_screenOutputPrefix << "Could not fill initial particle container. Abort." );
-    return StatusCode::FAILURE;
-  } else
-    ATH_MSG_VERBOSE ( m_screenOutputPrefix << "Initial particle container filled, initial size: " << initContainer.size() );
+  for ( const auto& simSelector : m_simSelectorSet ) {
+    simSelector->beginEvent();
+  }
 
   // update the routing chain selectors with the particles in the initial stack
-  ISFParticleContainer::iterator particleIter    = initContainer.begin();
-  ISFParticleContainer::iterator particleIterEnd = initContainer.end();
-  for ( ; particleIter != particleIterEnd; ++particleIter) {
+  for ( auto& particlePointer : simParticles ) {
+    auto& particle = *particlePointer;
 
     // identify the geoID of the particle
-    m_geoIDSvcQuick->identifyAndRegNextGeoID(**particleIter);
+    m_geoIDSvcQuick->identifyAndRegNextGeoID(particle);
     // the geoID at this point better makes sense :)
-    assertAtlasRegion( (**particleIter).nextGeoID() );
+    assertAtlasRegion( particle.nextGeoID() );
 
     // update all registered selectors (in all geoIDs) with this particle
-    updateAllSelectors( **particleIter);
+    updateAllSelectors(particle);
 
-    // inform the entry layer tool about this particle
-    ISF::EntryLayer layer = m_entryLayerToolQuick->registerParticle( **particleIter);
+    m_entryLayerTool->registerParticle(particle);
+  }
 
-    // if validation mode: fill the corresponding entry layer ROOT tree
-    if ( m_validationOutput && validEntryLayer(layer) ) {
-      fillPosValTree( m_t_entryLayerPos[layer], **particleIter);
-    }
+  size_t order = simParticles.size(); // FIXME: ugly hack to keep bit-wise identical output with prior FullG4 implementation :(
 
-  }
+  for ( auto& particlePtr: simParticles ) {
+    // FIXME: ugly hack to keep bit-wise identical output with prior FullG4 implementation :(
+    if (!m_hasOrderingTool) particlePtr->setOrder(order--); 
 
-  // move the particles from the initial stack to the different geoID stacks
-  particleIter    = initContainer.begin();
-  particleIterEnd = initContainer.end();
-  int iparticle=initContainer.size();
-  for ( ; particleIter != particleIterEnd; ++particleIter,iparticle--) {
-    //       - if a Selector selects a particle -> it is pushed onto the active stack
-    //       - if it is not selected -> pushed onto the hold stack
-    selectAndStore( *particleIter);
-    if (!m_orderingToolQuick) {
-      (*particleIter)->setOrder(iparticle);
-    }
+    selectAndStore(particlePtr);
   }
 
-  // empty initial stack
-  //  (don't delete the pointers, since they are now used in the local
-  //   particle container: m_particles)
-  initContainer.clear();
-
   return StatusCode::SUCCESS;
 }
 
@@ -511,8 +410,8 @@ void ISF::ParticleBrokerDynamicOnReadIn::push( ISFParticle *particlePtr, const I
   ISFParticle &particle = *particlePtr;
 
   if (parentPtr) {
-    Barcode::ParticleBarcode extrabc = parentPtr->getExtraBC();
-    particle.setExtraBC( extrabc );
+    int bcid = parentPtr->getBCID();
+    particle.setBCID(bcid);
   }
 
   // get the particle's next geoID
@@ -524,7 +423,7 @@ void ISF::ParticleBrokerDynamicOnReadIn::push( ISFParticle *particlePtr, const I
     geoID = m_geoIDSvcQuick->identifyAndRegNextGeoID(particle);
   }
   // inform the entry layer tool about this particle
-  ISF::EntryLayer layer = m_entryLayerToolQuick->registerParticle( particle );
+  ISF::EntryLayer layer = m_entryLayerTool->registerParticle( particle );
 
   // ---> if validation mode: fill the corresponding entry layer ROOT tree
   if ( m_validationOutput ) {
@@ -587,7 +486,7 @@ const ISF::ConstISFParticleVector& ISF::ParticleBrokerDynamicOnReadIn::popVector
 
       // if this particle has a different order or the maximum size of the return vector is reached
       //   -> don't add any more particles to the m_popParticles std::vector
-      if (  m_orderingToolQuick && ((curOrder != returnOrder) || (m_popParticles.size()>=maxVectorSize) ) ) break;
+      if ( m_hasOrderingTool && ((curOrder != returnOrder) || (m_popParticles.size()>=maxVectorSize) ) ) break;
 
       // add this particle to the, later returned, m_popParticles std::vector
       m_popParticles.push_back( curParticle);
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h
index 5755a5f58c6274381b190c166a8416ae5c12243c..4ea96f302dcff0f09898bdc51d62d69c051b3dc6 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h
@@ -41,7 +41,6 @@ class TTree;
 namespace ISF {
 
   class IGeoIDSvc;
-  class IStackFiller;
   class IEntryLayerTool;
   class ISimulationSelector;
 
@@ -70,7 +69,7 @@ namespace ISF {
       StatusCode  finalize();
 
       /** Initialize the particle broker */
-      StatusCode initializeEvent();
+      StatusCode initializeEvent(ISFParticleContainer&& simParticles);
 
       /** Finalize the event in the broker service */
       virtual StatusCode finalizeEvent();
@@ -122,19 +121,12 @@ namespace ISF {
           SimulationSelector that selects the particle */
       ISF::SimSvcID identifySimID( const ISF::ISFParticle* p);
 
-      /** store the simulation flavor of SimulationSelector that has selected the particle */
-      void storeSimulationFlavor( ISF::ISFParticle* p );
-
-      /** AthenaTool for reading in the initial (eg. EvGen)_particle list */
-      ToolHandle<IStackFiller>                  m_particleStackFiller;
-
       /** AthenaTool responsible for writing Calo/Muon Entry/Exit Layer collection */
       ToolHandle<IEntryLayerTool>               m_entryLayerTool;
-      IEntryLayerTool                          *m_entryLayerToolQuick;   //!< minimize Gaudi overhead
 
       /** AthenaTool responsible for proritizing the particles and determine their simulation order */
       ToolHandle<IParticleOrderingTool>         m_orderingTool;
-      IParticleOrderingTool                    *m_orderingToolQuick;//!< minimize Gaudi overhead
+      bool                                      m_hasOrderingTool;
 
       /** the geo identifier service used to route the particle into the right
           SimulationSelector chain */
@@ -180,8 +172,6 @@ namespace ISF {
       int                                       m_val_pdg;
       float                                     m_val_p;
       float                                     m_val_x, m_val_y, m_val_z;
-
-      ISF::SimulationFlavor                     m_simflavor;
   };
 
   /** Get the current stack size */
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..20ac7172610d795241c8a84c990469db0dd5beed
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.cxx
@@ -0,0 +1,364 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// TruthSvc.cxx, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+// class header
+#include "TruthSvc.h"
+// other ISF_HepMC includes
+#include "ISF_HepMC_Interfaces/ITruthStrategy.h"
+// ISF includes
+#include "ISF_Event/ITruthIncident.h"
+// Framework
+#include "GaudiKernel/ISvcLocator.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/SystemOfUnits.h"
+// Barcode
+#include "BarcodeInterfaces/IBarcodeSvc.h"
+// HepMC includes
+#include "HepMC/SimpleVector.h"
+#include "HepMC/GenParticle.h"
+#include "HepMC/GenEvent.h"
+#include "HepMC/GenVertex.h"
+// CLHEP includes
+#include "CLHEP/Geometry/Point3D.h"
+
+// DetectorDescription
+#include "AtlasDetDescr/AtlasRegionHelper.h"
+
+/** Constructor **/
+ISF::TruthSvc::TruthSvc(const std::string& name,ISvcLocator* svc) :
+  AthService(name,svc),
+  m_barcodeSvc("BarcodeSvc",name),
+  m_geoStrategies(),
+  m_numStrategies(),
+  m_skipIfNoChildren(true),
+  m_skipIfNoParentBarcode(true),
+  m_ignoreUndefinedBarcodes(false),
+  m_passWholeVertex(true),
+  m_forceEndVtxRegionsVec(),
+  m_forceEndVtx(),
+  m_quasiStableParticlesIncluded(false),
+  m_secondaryParticleBcOffset(Barcode::fUndefinedBarcode),
+  m_myLowestVertexBC(Barcode::fUndefinedBarcode)
+{
+    // the barcode service (used to compute Vertex Barco des)
+    declareProperty("BarcodeSvc",                        m_barcodeSvc              );
+    // MCTruth writing strategies
+    declareProperty("SkipIfNoChildren",                  m_skipIfNoChildren        );
+    declareProperty("SkipIfNoParentBarcode",             m_skipIfNoParentBarcode   );
+    declareProperty("IgnoreUndefinedBarcodes",           m_ignoreUndefinedBarcodes );
+    declareProperty("PassWholeVertices",                 m_passWholeVertex         );
+    // the truth strategies for the different AtlasDetDescr regions
+    declareProperty("BeamPipeTruthStrategies",           m_geoStrategyHandles[AtlasDetDescr::fAtlasForward] );
+    declareProperty("IDTruthStrategies",                 m_geoStrategyHandles[AtlasDetDescr::fAtlasID]      );
+    declareProperty("CaloTruthStrategies",               m_geoStrategyHandles[AtlasDetDescr::fAtlasCalo]    );
+    declareProperty("MSTruthStrategies",                 m_geoStrategyHandles[AtlasDetDescr::fAtlasMS]      );
+    declareProperty("CavernTruthStrategies",             m_geoStrategyHandles[AtlasDetDescr::fAtlasCavern]  );
+    // attach end-vertex if parent particle dies for the different AtlasDetDescr regions
+    declareProperty("ForceEndVtxInRegions",              m_forceEndVtxRegionsVec );
+
+    declareProperty("QuasiStableParticlesIncluded",      m_quasiStableParticlesIncluded);
+}
+
+ISF::TruthSvc::~TruthSvc()
+{}
+
+
+/** Query the interfaces. */
+StatusCode ISF::TruthSvc::queryInterface(const InterfaceID& riid, void** ppvInterface)
+{
+ if ( IID_ITruthSvc == riid )
+    *ppvInterface = (ITruthSvc*)this;
+ else  {
+   // Interface is not directly available: try out a base class
+   return Service::queryInterface(riid, ppvInterface);
+ }
+ addRef();
+ return StatusCode::SUCCESS;
+}
+
+
+/** framework methods */
+StatusCode ISF::TruthSvc::initialize()
+{
+    ATH_MSG_VERBOSE( "initialize()" );
+
+    // Screen output
+    ATH_MSG_DEBUG("--------------------------------------------------------");
+
+    // retrieve BarcodeSvc
+    if ( m_barcodeSvc.retrieve().isFailure() ) {
+      ATH_MSG_FATAL("Could not retrieve BarcodeService. Abort.");
+      return StatusCode::FAILURE;
+    }
+
+    // retrieve the strategies for each atlas region (Athena Alg Tools)
+    // and setup whether we want to write end-vertices in this region whenever a truth particle dies
+    for ( unsigned short geoID=AtlasDetDescr::fFirstAtlasRegion; geoID<AtlasDetDescr::fNumAtlasRegions; ++geoID) {
+      if ( m_geoStrategyHandles[geoID].retrieve().isFailure() ) {
+        ATH_MSG_FATAL("Could not retrieve TruthStrategy Tool Array for SimGeoID="
+                      << AtlasDetDescr::AtlasRegionHelper::getName(geoID) << ". Abort.");
+        return StatusCode::FAILURE;
+      }
+
+      // copy a pointer to the strategy instance to the local
+      // array of pointers (for faster access)
+      unsigned short curNumStrategies = m_geoStrategyHandles[geoID].size();
+      m_numStrategies[geoID] = curNumStrategies;
+      m_geoStrategies[geoID] = new ISF::ITruthStrategy*[curNumStrategies];
+      for ( unsigned short i = 0; i < curNumStrategies; ++i) {
+        m_geoStrategies[geoID][i] = &(*m_geoStrategyHandles[geoID][i]);
+      }
+
+      // create an end-vertex for all truth particles ending in the current AtlasRegion?
+      bool forceEndVtx = std::find( m_forceEndVtxRegionsVec.begin(),
+                                    m_forceEndVtxRegionsVec.end(),
+                                    geoID ) != m_forceEndVtxRegionsVec.end();
+      m_forceEndVtx[geoID] = forceEndVtx;
+    }
+
+    ATH_MSG_VERBOSE("initialize() successful");
+    return StatusCode::SUCCESS;
+}
+
+
+/** framework methods */
+StatusCode ISF::TruthSvc::finalize()
+{
+    ATH_MSG_VERBOSE("Finalizing ...");
+    return StatusCode::SUCCESS;
+}
+
+
+/** Initialize the TruthSvc and the truthSvc */
+StatusCode ISF::TruthSvc::initializeTruthCollection()
+{
+  m_myLowestVertexBC          = m_barcodeSvc->secondaryVertexBcOffset();
+  m_secondaryParticleBcOffset = m_barcodeSvc->secondaryParticleBcOffset();
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode ISF::TruthSvc::releaseEvent() {
+  return StatusCode::SUCCESS;
+}
+
+
+/** Register a truth incident */
+void ISF::TruthSvc::registerTruthIncident( ISF::ITruthIncident& ti) {
+
+  // pass whole vertex or individual child particles
+  ti.setPassWholeVertices(m_passWholeVertex);
+
+  // the GeoID
+  AtlasDetDescr::AtlasRegion geoID = ti.geoID();
+
+  // check geoID assigned to the TruthIncident
+  if ( !validAtlasRegion(geoID) ) {
+    ATH_MSG_ERROR("Unable to register truth incident with unknown SimGeoID="<< geoID);
+    return;
+  }
+
+  ATH_MSG_VERBOSE( "Registering TruthIncident for SimGeoID="
+                   << AtlasDetDescr::AtlasRegionHelper::getName(geoID) );
+
+  // number of child particles
+  unsigned short numSec = ti.numberOfChildren();
+  if ( m_skipIfNoChildren && (numSec==0) ) {
+    ATH_MSG_VERBOSE( "No child particles present in the TruthIncident,"
+                     << " will not record this TruthIncident.");
+    return;
+  }
+
+  // the parent particle -> get its barcode
+  Barcode::ParticleBarcode parentBC = ti.parentBarcode();
+  if ( m_skipIfNoParentBarcode && (parentBC==Barcode::fUndefinedBarcode) ) {
+    ATH_MSG_VERBOSE( "Parent particle in TruthIncident does not have a barcode,"
+                     << " will not record this TruthIncident.");
+    return;
+  }
+
+  // loop over registered truth strategies for given geoID
+  bool pass = false;
+  for ( unsigned short stratID=0; (!pass) && (stratID<m_numStrategies[geoID]); stratID++) {
+    // (*) test if given TruthIncident passes current strategy
+    pass = m_geoStrategies[geoID][stratID]->pass(ti);
+  }
+
+  if (pass) {
+    // at least one truth stategy returend true
+    //  -> record incident
+    recordIncidentToMCTruth( ti);
+
+  } else {
+    // none of the truth strategies returned true
+    //  -> child particles will NOT be added to the TruthEvent collection
+    
+    // attach parent particle end vertex if it gets killed by this interaction
+    if ( m_forceEndVtx[geoID] && !ti.parentSurvivesIncident() ) {
+      createGenVertexFromTruthIncident( ti);
+    }
+
+    //  -> assign shared barcode to all child particles (if barcode service supports it)
+    setSharedChildParticleBarcode( ti);
+  }
+
+  return;
+}
+
+/** Record the given truth incident to the MC Truth */
+void ISF::TruthSvc::recordIncidentToMCTruth( ISF::ITruthIncident& ti) {
+
+  Barcode::PhysicsProcessCode processCode = ti.physicsProcessCode();
+  Barcode::ParticleBarcode       parentBC = ti.parentBarcode();
+
+  // record the GenVertex
+  HepMC::GenVertex *vtx = createGenVertexFromTruthIncident(ti);
+
+  ATH_MSG_VERBOSE ( "Outgoing particles:" );
+  // update parent barcode and add it to the vertex as outgoing particle
+  Barcode::ParticleBarcode newPrimBC = m_barcodeSvc->incrementBarcode( parentBC, processCode);
+  if ( newPrimBC == Barcode::fUndefinedBarcode) {
+    if (m_ignoreUndefinedBarcodes) {
+      ATH_MSG_WARNING("Unable to generate new Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True");
+    } else {
+      ATH_MSG_ERROR("Unable to generate new Particle Barcode. Aborting");
+      abort();
+    }
+  }
+
+  HepMC::GenParticle *parentAfterIncident = ti.parentParticleAfterIncident( newPrimBC );
+  if(parentAfterIncident) {
+    ATH_MSG_VERBOSE ( "Parent After Incident: " << *parentAfterIncident);
+    vtx->add_particle_out( parentAfterIncident );
+  }
+
+  // add child particles to the vertex
+  unsigned short numSec = ti.numberOfChildren();
+  for ( unsigned short i=0; i<numSec; ++i) {
+
+    bool writeOutChild = m_passWholeVertex || ti.childPassedFilters(i);
+
+    if (writeOutChild) {
+      // generate a new barcode for the child particle
+      Barcode::ParticleBarcode secBC = m_barcodeSvc->newSecondary( parentBC, processCode);
+      if ( secBC == Barcode::fUndefinedBarcode) {
+        if (m_ignoreUndefinedBarcodes)
+          ATH_MSG_WARNING("Unable to generate new Secondary Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True");
+        else {
+          ATH_MSG_ERROR("Unable to generate new Secondary Particle Barcode. Aborting");
+          abort();
+        }
+      }
+      HepMC::GenParticle *p = ti.childParticle(i, secBC );
+      ATH_MSG_VERBOSE ( "Writing out " << i << "th child particle: " << *p);
+      // add particle to vertex
+      vtx->add_particle_out( p);
+
+      // Check to see if this is meant to be a "parent" vertex
+      if ( p && p->barcode() < m_secondaryParticleBcOffset ){
+        vtx->suggest_barcode( m_myLowestVertexBC );
+        ++m_myLowestVertexBC;
+        if (m_quasiStableParticlesIncluded){
+          ATH_MSG_VERBOSE( "Found a case of low barcode (" << p->barcode() << " < " <<
+                           m_secondaryParticleBcOffset  << " changing vtx barcode to " << m_myLowestVertexBC+1 );
+        } else {
+          ATH_MSG_WARNING( "Modifying vertex barcode, but no apparent quasi-stable particle simulation enabled." );
+          ATH_MSG_WARNING( "This means that you have encountered a very strange configuration.  Watch out!" );
+        }
+      }
+    } // <-- if write out child particle
+    else {
+      ATH_MSG_VERBOSE ( "Not writing out " << i << "th child particle." );
+    }
+
+  } // <-- loop over all child particles
+}
+
+/** Record the given truth incident to the MC Truth */
+HepMC::GenVertex *ISF::TruthSvc::createGenVertexFromTruthIncident( ISF::ITruthIncident& ti) {
+
+  Barcode::PhysicsProcessCode processCode = ti.physicsProcessCode();
+  Barcode::ParticleBarcode       parentBC = ti.parentBarcode();
+
+  std::vector<double> weights(1);
+  Barcode::ParticleBarcode primaryBC = parentBC % m_barcodeSvc->particleGenerationIncrement();
+  weights[0] = static_cast<double>( primaryBC );
+
+  // Check for a previous end vertex on this particle.  If one existed, then we should put down next to this
+  //  a new copy of the particle.  This is the agreed upon version of the quasi-stable particle truth, where
+  //  the vertex at which we start Q-S simulation no longer conserves energy, but we keep both copies of the
+  //  truth particles
+  HepMC::GenParticle *parent = ti.parentParticle();
+  if (!parent) {
+    ATH_MSG_ERROR("Unable to write particle interaction to MC truth due to missing parent HepMC::GenParticle instance");
+    abort();
+  }
+  HepMC::GenEvent *mcEvent = parent->parent_event();
+  if (!mcEvent) {
+    ATH_MSG_ERROR("Unable to write particle interaction to MC truth due to missing parent HepMC::GenEvent instance");
+    abort();
+  }
+
+  // generate vertex
+  Barcode::VertexBarcode vtxbcode = m_barcodeSvc->newVertex( parentBC, processCode );
+  if ( vtxbcode == Barcode::fUndefinedBarcode) {
+    if (m_ignoreUndefinedBarcodes) {
+      ATH_MSG_WARNING("Unable to generate new Truth Vertex Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True");
+    } else {
+      ATH_MSG_ERROR("Unable to generate new Truth Vertex Barcode. Aborting");
+      abort();
+    }
+  }
+  int vtxID = 1000 + static_cast<int>(processCode);
+  HepMC::GenVertex *vtx = new HepMC::GenVertex( ti.position(), vtxID, weights );
+  vtx->suggest_barcode( vtxbcode );
+
+  if (parent->end_vertex()){
+    if(!m_quasiStableParticlesIncluded) {
+      ATH_MSG_WARNING("Parent particle found with an end vertex attached.  This should only happen");
+      ATH_MSG_WARNING("in the case of simulating quasi-stable particles.  That functionality");
+      ATH_MSG_WARNING("is not yet validated in ISF, so you'd better know what you're doing.");
+      ATH_MSG_WARNING("Will delete the old vertex and swap in the new one.");
+    }
+
+    // Remove the old vertex from the event
+    parent->parent_event()->remove_vertex( parent->end_vertex() );
+
+    // Now add the new vertex to the new parent
+    vtx->add_particle_in( parent );
+    ATH_MSG_VERBOSE ( "QS End Vertex representing process: " << processCode << ", for parent with barcode "<<parentBC<<". Creating." );
+    ATH_MSG_VERBOSE ( "Parent: " << *parent);
+  } else { // Normal simulation
+    // add parent particle to vtx
+    vtx->add_particle_in( parent );
+    ATH_MSG_VERBOSE ( "End Vertex representing process: " << processCode << ", for parent with barcode "<<parentBC<<". Creating." );
+    ATH_MSG_VERBOSE ( "Parent: " << *parent);
+  }
+
+  mcEvent->add_vertex( vtx );
+
+  return vtx;
+}
+
+/** Set shared barcode for child particles particles */
+void ISF::TruthSvc::setSharedChildParticleBarcode( ISF::ITruthIncident& ti) {
+  Barcode::PhysicsProcessCode processCode = ti.physicsProcessCode();
+  Barcode::ParticleBarcode       parentBC = ti.parentBarcode();
+
+  ATH_MSG_VERBOSE ( "End Vertex representing process: " << processCode << ". TruthIncident failed cuts. Skipping.");
+
+  // generate one new barcode for all child particles
+  Barcode::ParticleBarcode childBC = m_barcodeSvc->sharedChildBarcode( parentBC, processCode);
+
+  // propagate this barcode into the TruthIncident only if
+  // it is a proper barcode, ie !=fUndefinedBarcode
+  if (childBC != Barcode::fUndefinedBarcode) {
+    ti.setAllChildrenBarcodes( childBC );
+  }
+}
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.h b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0541c4ff54474997d28ecaa6015db86e38d9d67
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.h
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// TruthSvc.h, (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef ISF_SERVICES_HEPMC_TRUTHSVC_H
+#define ISF_SERVICES_HEPMC_TRUTHSVC_H 1
+
+// STL includes
+#include <string>
+
+// FrameWork includes
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "AthenaBaseComps/AthService.h"
+
+// ISF include
+#include "ISF_Interfaces/ITruthSvc.h"
+
+// DetectorDescription
+#include "AtlasDetDescr/AtlasRegion.h"
+
+// Barcode
+#include "BarcodeEvent/Barcode.h"
+
+// McEventCollection
+#include "GeneratorObjects/McEventCollection.h"
+
+// forward declarations
+class StoreGateSvc;
+
+namespace Barcode {
+  class IBarcodeSvc;
+}
+
+namespace HepMC {
+  class GenEvent;
+}
+
+namespace ISF {
+
+  class ITruthStrategy;
+  typedef ToolHandleArray<ITruthStrategy>     TruthStrategyArray;
+
+  /** @class TruthSvc
+
+      HepMC based version of the ISF::ITruthSvc,
+      currently it takes an ITruthIncident base class
+
+
+      @author Andreas.Salzburger -at- cern.ch , Elmar.Ritsch -at- cern.ch
+  */
+  class TruthSvc : public AthService, public ITruthSvc {
+  public:
+
+    //** Constructor with parameters */
+    TruthSvc( const std::string& name, ISvcLocator* pSvcLocator );
+
+    /** Destructor */
+    virtual ~TruthSvc();
+
+    /** Athena algorithm's interface method initialize() */
+    StatusCode  initialize() override final;
+    /** Athena algorithm's interface method finalize() */
+    StatusCode  finalize() override final;
+
+    /** Register a truth incident */
+    void registerTruthIncident( ITruthIncident& truthincident) override final;
+
+    /** Initialize the Truth Svc at the beginning of each event */
+    StatusCode initializeTruthCollection() override final;
+
+    /** Finalize the Truth Svc at the end of each event*/
+    StatusCode releaseEvent() override final;
+
+    /** Query the interfaces. **/
+    StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface );
+
+  private:
+    /** Record the given truth incident to the MC Truth */
+    void recordIncidentToMCTruth( ITruthIncident& truthincident);
+    /** Record and end vertex to the MC Truth for the parent particle */
+    HepMC::GenVertex *createGenVertexFromTruthIncident( ITruthIncident& truthincident);
+
+    /** Set shared barcode for child particles */
+    void setSharedChildParticleBarcode( ITruthIncident& truthincident);
+
+    ServiceHandle<Barcode::IBarcodeSvc>       m_barcodeSvc;           //!< The Barcode service
+
+    /** the truth strategie applied (as AthenaToolHandle Array) */
+    TruthStrategyArray                        m_geoStrategyHandles[AtlasDetDescr::fNumAtlasRegions];
+    /** for faster access: using an internal pointer to the actual ITruthStrategy instances */
+    ITruthStrategy**                          m_geoStrategies[AtlasDetDescr::fNumAtlasRegions];
+    unsigned short                            m_numStrategies[AtlasDetDescr::fNumAtlasRegions];
+
+    /** MCTruth steering */
+    bool                                      m_skipIfNoChildren;       //!< do not record incident if numChildren==0
+    bool                                      m_skipIfNoParentBarcode;  //!< do not record if parentBarcode==fUndefinedBarcode
+    bool                                      m_ignoreUndefinedBarcodes;//!< do/don't abort if retrieve an undefined barcode
+
+    bool                                      m_storeExtraBCs;
+    bool                                      m_passWholeVertex;
+
+    std::vector<bool>                         m_forceEndVtxRegionsVec; //!< property containing AtlasRegions for which
+                                                                              //   to write end-vtx
+    bool                                      m_forceEndVtx[AtlasDetDescr::fNumAtlasRegions]; //!< attach end vertex to
+                                                                                                     //   all parent particles if they die
+
+    bool                                      m_quasiStableParticlesIncluded; //!< does this job simulate quasi-stable particles.
+
+    Barcode::ParticleBarcode                  m_secondaryParticleBcOffset;
+    Barcode::VertexBarcode                    m_myLowestVertexBC;
+
+  };
+}
+
+
+#endif //> !ISF_SERVICES_HEPMC_TRUTHSVC_H
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx
index 0ab8bfbcee77d8acfe8eb1eff066950306c449bf..5c8b6a298efec8fd1007341c6311591fc6fdd0ea 100644
--- a/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx
+++ b/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx
@@ -1,23 +1,29 @@
 #include "GaudiKernel/DeclareFactoryEntries.h"
-#include "../ParticleBrokerDynamicOnReadIn.h"
-#include "../SimHitSvc.h"
-#include "../ParticleKillerSimSvc.h"
-#include "../ISFEnvelopeDefSvc.h"
 #include "../AFIIEnvelopeDefSvc.h"
 #include "../GeoIDSvc.h"
+#include "../InputConverter.h"
+#include "../ISFEnvelopeDefSvc.h"
+#include "../ParticleBrokerDynamicOnReadIn.h"
+#include "../ParticleKillerSimSvc.h"
+#include "../SimHitSvc.h"
+#include "../TruthSvc.h"
 
-DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleBrokerDynamicOnReadIn    )
-DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , SimHitSvc                     )
-DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleKillerSimSvc          )
-DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ISFEnvelopeDefSvc             )
 DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , AFIIEnvelopeDefSvc            )
 DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , GeoIDSvc                      )
+DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , InputConverter                )
+DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ISFEnvelopeDefSvc             )
+DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleBrokerDynamicOnReadIn )
+DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleKillerSimSvc          )
+DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , SimHitSvc                     )
+DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , TruthSvc                      )
 
 DECLARE_FACTORY_ENTRIES( ISF_Services ) {
-  DECLARE_NAMESPACE_SERVICE( ISF ,  ParticleBrokerDynamicOnReadIn    )
-  DECLARE_NAMESPACE_SERVICE( ISF ,  SimHitSvc                     )
-  DECLARE_NAMESPACE_SERVICE( ISF ,  ParticleKillerSimSvc          )
-  DECLARE_NAMESPACE_SERVICE( ISF ,  ISFEnvelopeDefSvc             )
   DECLARE_NAMESPACE_SERVICE( ISF ,  AFIIEnvelopeDefSvc            )
   DECLARE_NAMESPACE_SERVICE( ISF ,  GeoIDSvc                      )
+  DECLARE_NAMESPACE_SERVICE( ISF ,  InputConverter                )
+  DECLARE_NAMESPACE_SERVICE( ISF ,  ISFEnvelopeDefSvc             )
+  DECLARE_NAMESPACE_SERVICE( ISF ,  ParticleBrokerDynamicOnReadIn )
+  DECLARE_NAMESPACE_SERVICE( ISF ,  ParticleKillerSimSvc          )
+  DECLARE_NAMESPACE_SERVICE( ISF ,  SimHitSvc                     )
+  DECLARE_NAMESPACE_SERVICE( ISF ,  TruthSvc                      )
 }
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/test/ISF_Services.xml b/Simulation/ISF/ISF_Core/ISF_Services/test/ISF_Services.xml
new file mode 100644
index 0000000000000000000000000000000000000000..50fbad5b5ab290662a95b59daef05b7b6e8a8a08
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/test/ISF_Services.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<atn>
+   <TEST name="UnitTests" type="makecheck">
+      <package>Simulation/ISF/ISF_Core/ISF_Services</package>
+      <author>Elmar Ritsch</author>
+      <mailto>atlas-srl-Sim-ISF-Core</mailto>
+      <expectations>
+         <errorMessage>Athena exited abnormally</errorMessage>
+         <errorMessage>differ</errorMessage>
+         <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage>
+         <successMessage>check ok</successMessage>
+         <returnValue>0</returnValue>
+      </expectations>
+   </TEST>
+</atn>
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/test/InputConverter_test.cxx b/Simulation/ISF/ISF_Core/ISF_Services/test/InputConverter_test.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9226cee223bdb538980ad2d2663ca99d89a9a04e
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/test/InputConverter_test.cxx
@@ -0,0 +1,452 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @author Elmar Ritsch <Elmar.Ritsch@cern.ch>
+ * @date June, 2016
+ * @brief Tests for ISF::InputConverter.
+ */
+
+#undef NDEBUG
+
+// Tested service
+#include "../src/InputConverter.h"
+
+// Framework
+#include "GaudiKernel/PhysicalConstants.h"
+#include "GaudiKernel/DeclareFactoryEntries.h"
+#include "GaudiKernel/Bootstrap.h"
+#include "GaudiKernel/IProperty.h"
+#include "GaudiKernel/ISvcManager.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/IAppMgrUI.h"
+#include "GaudiKernel/SmartIF.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+
+// Framework testing
+#include "TestTools/initGaudi.h"
+
+// Google Test
+#include "gtest/gtest.h"
+// Google Mock
+#include "gmock/gmock.h"
+
+// ISF
+#include "ISF_Event/ISFParticle.h"
+#include "ISF_HepMC_Interfaces/IGenParticleFilter.h"
+
+// Amg
+#include "GeoPrimitives/GeoPrimitives.h"
+
+// HepMC
+#include "HepMC/GenParticle.h"
+#include "HepMC/GenVertex.h"
+
+// STL includes
+#include <cstdlib> // quick_exit
+
+
+namespace ISFTesting {
+
+// Athena Tool to emulate a GenParticleFilter
+class MockFilterTool : public AthAlgTool,
+                       public ISF::IGenParticleFilter { 
+    
+ public: 
+  MockFilterTool(const std::string& type, const std::string& name, const IInterface* parent)
+    : AthAlgTool(type,name,parent)
+  { declareInterface<ISF::IGenParticleFilter>(this); };
+
+  virtual ~MockFilterTool() {};
+
+  // mock method which will be called by tested code
+  MOCK_CONST_METHOD1(pass, bool(const HepMC::GenParticle&));
+}; 
+
+DECLARE_TOOL_FACTORY( MockFilterTool )
+
+
+class InputConverter_test: public ::testing::Test {
+
+ protected:
+  virtual void SetUp() override {
+    m_appMgr = Gaudi::createApplicationMgr();
+    ASSERT_TRUE( m_appMgr!=nullptr );
+
+    m_svcLoc = m_appMgr;
+    ASSERT_TRUE( m_svcLoc.isValid() );
+
+    m_svcMgr = m_appMgr;
+    ASSERT_TRUE( m_svcMgr.isValid() );
+
+    m_propMgr = m_appMgr;
+    ASSERT_TRUE( m_propMgr.isValid() );
+    ASSERT_TRUE( m_propMgr->setProperty( "EvtSel",         "NONE" ).isSuccess() );
+    ASSERT_TRUE( m_propMgr->setProperty( "JobOptionsType", "NONE" ).isSuccess() );
+
+    m_toolSvc = m_svcLoc->service("ToolSvc");
+    ASSERT_TRUE( m_toolSvc.isValid() );
+
+    ASSERT_TRUE( m_appMgr->configure().isSuccess() );
+    ASSERT_TRUE( m_appMgr->initialize().isSuccess() );
+
+    // the tested AthenaService
+    m_svc = m_svcLoc->service("ISF::InputConverter/InputConverter");
+    ASSERT_TRUE( m_svc.isValid() );
+    ASSERT_TRUE( m_svc->setProperties().isSuccess() );
+    ASSERT_TRUE( m_svc->configure().isSuccess() );
+  }
+
+  virtual void TearDown() override {
+   // @TODO: for newer Gaudi versions (atlasoff rel 21+)
+    // an approach like this would be much cleaner
+    // than releasing the tools by hand in the individual
+    // test functions
+    //const auto tools = m_toolSvc->getTools();
+    //for (auto& tool: tools) {
+    //  ASSERT_TRUE( TearDownTool(tool).isSuccess() );
+    //}
+
+    m_svcMgr->removeService(m_svc);
+    ASSERT_TRUE( m_svc->finalize().isSuccess() );
+    ASSERT_TRUE( m_svc->terminate().isSuccess() );
+    ReleaseSmartIFComponent(m_svc);
+
+    ASSERT_TRUE( m_appMgr->finalize().isSuccess() );
+    ASSERT_TRUE( m_appMgr->terminate().isSuccess() );
+    Gaudi::setInstance( static_cast<IAppMgrUI*>(nullptr)) ;
+  }
+
+  MockFilterTool* SetUpMockFilterTool(const std::string& name) const {
+    IAlgTool* mockFilterITool = nullptr;
+    m_toolSvc->retrieveTool(name, mockFilterITool);
+
+    MockFilterTool* mockFilterTool = dynamic_cast<MockFilterTool*>(mockFilterITool);
+    return mockFilterTool;
+  }
+
+  void ReleaseSmartIFComponent(IInterface* comp) {
+    size_t finalRefCount = 1; // keep one reference for the SmartIF destructor
+    for (size_t refCount = comp->refCount(); refCount>finalRefCount; refCount--) {
+      comp->release();
+    }
+  }
+
+  // release given tool from the ToolService until it reaches a
+  // reference count of 1
+  StatusCode TearDownTool(IAlgTool* tool) const {
+    for (size_t refCount = tool->refCount(); refCount>0; refCount--) {
+      StatusCode sc = m_toolSvc->releaseTool(tool);
+      if ( !sc.isSuccess() ) {
+        return StatusCode::FAILURE;
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  //
+  // accessors for private methods
+  // NB: This works because InputConverter_test is a friend
+  //     of the tested InputConverter service
+  //
+  template<typename... Args>
+  ISF::ISFParticle* convertParticle(Args&&... args) const {
+    return m_svc->convertParticle(std::forward<Args>(args)...);
+  }
+
+  template<typename... Args>
+  bool passesFilters(Args&&... args) const {
+    return m_svc->passesFilters(std::forward<Args>(args)...);
+  }
+
+  //
+  // protected member variables 
+  //
+
+  // Core Gaudi components
+  IAppMgrUI*             m_appMgr = nullptr;
+  SmartIF<ISvcLocator>   m_svcLoc;
+  SmartIF<ISvcManager>   m_svcMgr;
+  SmartIF<IToolSvc>      m_toolSvc;
+  SmartIF<IProperty>     m_propMgr;
+
+  SmartIF<ISF::InputConverter>   m_svc; // the tested AthenaService
+
+};  // InputConverter_test fixture
+
+
+TEST_F(InputConverter_test, initialize_empty) {
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+}
+
+
+TEST_F(InputConverter_test, convertParticle_nullptr) {
+  ISF::ISFParticle* expected = nullptr;
+  int bcid = 1;
+  ASSERT_EQ( expected, convertParticle(nullptr, bcid) );
+}
+
+
+TEST_F(InputConverter_test, convertParticle_without_production_vertex) {
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  HepMC::GenParticle* genPart = new HepMC::GenParticle(mom,
+                                                       123, // pdg
+                                                       1 // status
+                                                      );
+  ISF::ISFParticle* expected = nullptr;
+  int bcid = 99;
+  ASSERT_EQ( expected, convertParticle(genPart, bcid) );
+  delete genPart;
+}
+
+
+TEST_F(InputConverter_test, convertParticle_using_generated_mass) {
+  m_svc->setProperty("UseGeneratedParticleMass", "True");
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  // dynamic allocation necessary as particle ownership is
+  // handed over to a HepMC::GenVertex later
+  HepMC::GenParticle* genPart = new HepMC::GenParticle(mom,
+                                                       11, // pdg id (e-)
+                                                       1 // status
+                                                      );
+  genPart->set_generated_mass(1234.56);
+  genPart->suggest_barcode(9876352);
+
+  HepMC::FourVector pos(9.8, 7.65, 4.3, 0.321); // NB: 4th component is time*c
+  int vtx_id = -123;
+  HepMC::GenVertex prodVtx(pos, vtx_id);
+  prodVtx.add_particle_out(genPart);
+
+  Amg::Vector3D expectedPos(9.8, 7.65, 4.3);
+  Amg::Vector3D expectedMom(12.3, 45.6, 78.9);
+  ISF::DetRegionSvcIDPair expectedHistory(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID);
+  auto expectedTruthBinding = new ISF::TruthBinding(genPart);
+  ISF::ISFParticle expected(expectedPos,
+                            expectedMom,
+                            1234.56,
+                            -1., // charge
+                            11, // pdg id
+                            0.321/Gaudi::Units::c_light, // time
+                            expectedHistory,
+                            563, // bcid
+                            9876352, // barcode
+                            expectedTruthBinding
+                            );
+
+  int bcid = 563;
+  // call the InputConverter's private method
+  ISF::ISFParticle* returned = convertParticle(genPart, bcid);
+  ASSERT_TRUE( returned );
+
+  ASSERT_EQ( expected, *returned );
+}
+
+
+TEST_F(InputConverter_test, convertParticle_using_particleDataTable_photon) {
+  m_svc->setProperty("UseGeneratedParticleMass", "False");
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  // dynamic allocation necessary as particle ownership is
+  // handed over to a HepMC::GenVertex later
+  HepMC::GenParticle* genPart = new HepMC::GenParticle(mom,
+                                                       22, // pdg id (gamma)
+                                                       1 // status
+                                                      );
+  genPart->set_generated_mass(1234.56); // should be ignored later on
+  genPart->suggest_barcode(9876352);
+
+  HepMC::FourVector pos(9.8, 7.65, 4.3, 0.321); // NB: 4th component is time*c
+  int vtx_id = -123;
+  HepMC::GenVertex prodVtx(pos, vtx_id);
+  prodVtx.add_particle_out(genPart);
+
+  Amg::Vector3D expectedPos(9.8, 7.65, 4.3);
+  Amg::Vector3D expectedMom(12.3, 45.6, 78.9);
+  ISF::DetRegionSvcIDPair expectedHistory(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID);
+  auto expectedTruthBinding = new ISF::TruthBinding(genPart);
+  ISF::ISFParticle expected(expectedPos,
+                            expectedMom,
+                            0., // mass from ParticleDataTable
+                            0., // charge
+                            22, // pdg id
+                            0.321/Gaudi::Units::c_light, // time
+                            expectedHistory,
+                            0, // bcid
+                            9876352, // barcode
+                            expectedTruthBinding
+                            );
+
+  int bcid = 0;
+  // call the InputConverter's private method
+  ISF::ISFParticle* returned = convertParticle(genPart, bcid);
+  ASSERT_TRUE( returned );
+
+  ASSERT_EQ( expected, *returned );
+}
+
+
+TEST_F(InputConverter_test, convertParticle_using_particleDataTable_electron) {
+  m_svc->setProperty("UseGeneratedParticleMass", "False");
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  // dynamic allocation necessary as particle ownership is
+  // handed over to a HepMC::GenVertex later
+  HepMC::GenParticle* genPart = new HepMC::GenParticle(mom,
+                                                       11, // pdg id (e-)
+                                                       1 // status
+                                                      );
+  genPart->set_generated_mass(1234.56); // should be ignored later on
+  genPart->suggest_barcode(9876352);
+
+  HepMC::FourVector pos(9.8, 7.65, 4.3, 0.321); // NB: 4th component is time*c
+  int vtx_id = -123;
+  HepMC::GenVertex prodVtx(pos, vtx_id);
+  prodVtx.add_particle_out(genPart);
+
+  Amg::Vector3D expectedPos(9.8, 7.65, 4.3);
+  Amg::Vector3D expectedMom(12.3, 45.6, 78.9);
+  ISF::DetRegionSvcIDPair expectedHistory(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID);
+  auto expectedTruthBinding = new ISF::TruthBinding(genPart);
+  ISF::ISFParticle expected(expectedPos,
+                            expectedMom,
+                            0.51099891/Gaudi::Units::MeV, // from particle
+                            -1., // charge
+                            11, // pdg id
+                            0.321/Gaudi::Units::c_light, // time
+                            expectedHistory,
+                            11, // bcid
+                            9876352, // barcode
+                            expectedTruthBinding
+                            );
+
+  int bcid = 11;
+  // call the InputConverter's private method
+  ISF::ISFParticle* returned = convertParticle(genPart, bcid);
+  std::cout << " EMASS=" << std::setprecision(20) << returned->mass() << std::endl;
+  ASSERT_TRUE( returned );
+
+  ASSERT_EQ( expected, *returned );
+}
+
+
+TEST_F(InputConverter_test, passesFilters_empty_filters_defaultconstructed_genpart) {
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  const HepMC::GenParticle genPart{};
+  ASSERT_TRUE( passesFilters(genPart) );
+}
+
+
+TEST_F(InputConverter_test, passesFilters_empty_filters) {
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  HepMC::GenParticle genPart(mom,
+                              11, // pdg id (e-)
+                              1 // status
+                             );
+  genPart.set_generated_mass(1234.56);
+  genPart.suggest_barcode(9876352);
+  const HepMC::GenParticle constGenPart(std::move(genPart));
+
+  ASSERT_TRUE( passesFilters(constGenPart) );
+}
+
+
+TEST_F(InputConverter_test, passesFilters_one_pass_filter) {
+  // retrieve mockable GenParticleFilter tool and point InputConverter to the same instance
+  MockFilterTool* filterTool = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilter");
+  ASSERT_TRUE( filterTool );
+  m_svc->setProperty("GenParticleFilters", "['ISFTesting::MockFilterTool/DummyFilter']");
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  const HepMC::GenParticle genPart{};
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  HepMC::GenParticle genPart2(mom,
+                              11, // pdg id (e-)
+                              1 // status
+                              );
+
+  EXPECT_CALL(*filterTool, pass(genPart))
+      .Times(1)
+      .WillOnce(::testing::Return(true));
+
+  ASSERT_TRUE( passesFilters(genPart) );
+
+  ASSERT_TRUE( TearDownTool(filterTool).isSuccess() );
+}
+
+
+TEST_F(InputConverter_test, passesFilters_one_nonpass_filter) {
+  // retrieve mockable GenParticleFilter tool and point InputConverter to the same instance
+  MockFilterTool* filterTool = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilter");
+  ASSERT_TRUE( filterTool );
+  m_svc->setProperty("GenParticleFilters", "['ISFTesting::MockFilterTool/DummyFilter']");
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  const HepMC::GenParticle genPart{};
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  HepMC::GenParticle genPart2(mom,
+                              11, // pdg id (e-)
+                              1 // status
+                              );
+
+  EXPECT_CALL(*filterTool, pass(genPart))
+      .Times(1)
+      .WillOnce(::testing::Return(false));
+
+  ASSERT_FALSE( passesFilters(genPart) );
+
+  ASSERT_TRUE( TearDownTool(filterTool).isSuccess() );
+}
+
+
+TEST_F(InputConverter_test, passesFilters_two_filters) {
+  // retrieve mockable GenParticleFilter tool and point InputConverter to the same instance
+  MockFilterTool* filterTool1 = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilterZ");
+  MockFilterTool* filterTool2 = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilterY");
+  ASSERT_TRUE( filterTool1 );
+  ASSERT_TRUE( filterTool2 );
+  m_svc->setProperty("GenParticleFilters", "['ISFTesting::MockFilterTool/DummyFilterZ', 'ISFTesting::MockFilterTool/DummyFilterY']");
+  ASSERT_TRUE( m_svc->initialize().isSuccess() );
+
+  const HepMC::GenParticle genPart{};
+  HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12);
+  HepMC::GenParticle genPart2(mom,
+                              11, // pdg id (e-)
+                              1 // status
+                              );
+
+  EXPECT_CALL(*filterTool1, pass(genPart))
+      .Times(1)
+      .WillOnce(::testing::Return(true));
+
+  EXPECT_CALL(*filterTool2, pass(genPart))
+      .Times(1)
+      .WillOnce(::testing::Return(true));
+
+  ASSERT_TRUE( passesFilters(genPart) );
+
+  // apparently it's our responsibility to reduce the reference
+  // counter to 0 to make sure the tools are properly destructed
+  ASSERT_TRUE( m_toolSvc->releaseTool(filterTool1).isSuccess() );
+  ASSERT_TRUE( m_toolSvc->releaseTool(filterTool1).isSuccess() );
+  ASSERT_TRUE( m_toolSvc->releaseTool(filterTool2).isSuccess() );
+  ASSERT_TRUE( m_toolSvc->releaseTool(filterTool2).isSuccess() );
+}
+
+} // <-- namespace ISFTesting
+
+int main(int argc, char *argv[]) {
+  ::testing::InitGoogleTest( &argc, argv );
+
+  // gets stuck forever while trying to finalize boost crap inside SGTools:
+  //return RUN_ALL_TESTS();
+  // skips proper finalization:
+  std::quick_exit( RUN_ALL_TESTS() );
+}
diff --git a/Simulation/ISF/ISF_Core/ISF_Services/test/gtest_post_check.sh b/Simulation/ISF/ISF_Core/ISF_Services/test/gtest_post_check.sh
new file mode 100755
index 0000000000000000000000000000000000000000..66b31db557526776de1a4fd0cddcb8ed0ed71fd7
--- /dev/null
+++ b/Simulation/ISF/ISF_Core/ISF_Services/test/gtest_post_check.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+LOGFILE=${1}
+FAILUREPATTERN='\[  FAILED  \].*'
+ALIVEPATTERN='\[  PASSED  \].*'
+
+#cat ${LOGFILE}
+
+if ! grep -xq "$ALIVEPATTERN" ${LOGFILE}
+then
+    echo -e "\nUnable to find gtest signature '${ALIVEPATTERN}' in test output!"
+    echo -e "ERROR: Tests failed!\n"
+    exit 1
+fi
+
+if grep -xq "$FAILUREPATTERN" ${LOGFILE}
+then
+    echo -e "\nFound failure pattern '${FAILUREPATTERN}' in test output!"
+    echo -e "ERROR: Tests failed!\n"
+    exit 1
+fi