diff --git a/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py b/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py
index 292682b4f23b9aa149672aca026e305f8f0d2b4f..7e24163ad90fc101363f39bc33e2c48670b3dd9a 100644
--- a/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py
+++ b/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py
@@ -8,6 +8,7 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 from G4FaserServices.G4FaserServicesConfigNew import DetectorGeometrySvcCfg, PhysicsListSvcCfg
 from G4FaserTools.G4FaserToolsConfigNew import SensitiveDetectorMasterToolCfg
 from G4FaserServices.G4FaserUserActionConfigNew import UserActionSvcCfg
+from G4FaserServices.G4FaserUserActionConfigNew import UserActionMaterialStepRecorderSvcCfg
 # from G4AtlasApps.G4Atlas_MetadataNew import writeSimulationParametersMetadata
 #
 #  Framework utilities
@@ -122,3 +123,108 @@ def G4FaserAlgCfg(ConfigFlags, name='G4FaserAlg', **kwargs):
     result.addEventAlgo(G4FaserAlg(name, **kwargs))
     return result
 
+def G4FaserMaterialStepRecorderAlgCfg(ConfigFlags, name='G4FaserAlg', **kwargs):
+    #
+    #  add Services to G4AtlasAlg
+    #
+    result = DetectorGeometrySvcCfg(ConfigFlags)
+    kwargs.setdefault('DetGeoSvc', result.getService("DetectorGeometrySvc"))
+    #
+    #  MC particle container names
+    #
+    kwargs.setdefault("InputTruthCollection", "GEN_EVENT") 
+    kwargs.setdefault("OutputTruthCollection", "TruthEvent")
+    #
+    #  Option to free memory by dropping GeoModel after construction
+    #
+    # if ConfigFlags.Sim.ReleaseGeoModel:
+    kwargs.setdefault('ReleaseGeoModel', ConfigFlags.Sim.ReleaseGeoModel)
+    #
+    #  Record the particle flux during the simulation
+    #
+    #if ConfigFlags.Sim.RecordFlux:
+    kwargs.setdefault('RecordFlux' , ConfigFlags.Sim.RecordFlux)
+    #
+    #  Treatment of bad events
+    #
+    # if ConfigFlags.Sim.FlagAbortedEvents:
+        ## default false
+    kwargs.setdefault('FlagAbortedEvents' ,ConfigFlags.Sim.FlagAbortedEvents)
+    if ConfigFlags.Sim.FlagAbortedEvents and ConfigFlags.Sim.KillAbortedEvents:
+            print('WARNING When G4AtlasAlg.FlagAbortedEvents is True G4AtlasAlg.KillAbortedEvents should be False!!! Setting G4AtlasAlg.KillAbortedEvents = False now!')
+            kwargs.setdefault('KillAbortedEvents' ,False)
+    # if  ConfigFlags.Sim.KillAbortedEvents:
+        ## default true
+    kwargs.setdefault('KillAbortedEvents' ,ConfigFlags.Sim.KillAbortedEvents)
+    #
+    #  Random numbers
+    #
+    from RngComps.RandomServices import AthEngines, RNG
+    if ConfigFlags.Random.Engine in AthEngines.keys():
+        result.merge(RNG(ConfigFlags.Random.Engine, name="AthRNGSvc"))
+        kwargs.setdefault("AtRndmGenSvc",result.getService("AthRNGSvc"))
+
+    kwargs.setdefault("RandomGenerator", "athena")
+    #
+    #  Multi-threading settings
+    #
+    is_hive = ConfigFlags.Concurrency.NumThreads > 1
+    kwargs.setdefault('MultiThreading', is_hive)
+    #
+    #  What truth information to save?
+    #
+    accMCTruth = FaserTruthServiceCfg(ConfigFlags)
+    result.merge(accMCTruth)
+    kwargs.setdefault('TruthRecordService', result.getService("FaserISF_TruthService"))
+    #kwargs.setdefault('TruthRecordService', ConfigFlags.Sim.TruthStrategy) # TODO need to have manual override (simFlags.TruthStrategy.TruthServiceName())
+    #
+    #  Locates detector region for space points (no longer used by G4FaserAlg)
+    #
+    accGeoID = FaserGeoIDSvcCfg(ConfigFlags)
+    result.merge(accGeoID)
+    #kwargs.setdefault('GeoIDSvc', result.getService('ISF_FaserGeoIDSvc'))
+    #
+    #  Converts generator particles to a proprietary type managed by ISF
+    #
+    accInputConverter = FaserInputConverterCfg(ConfigFlags)
+    result.merge(accInputConverter)
+    kwargs.setdefault('InputConverter', result.getService("ISF_FaserInputConverter"))
+    #
+    # Sensitive detector master tool
+    #
+    accSensitiveDetector = SensitiveDetectorMasterToolCfg(ConfigFlags)
+    result.merge(accSensitiveDetector)
+    kwargs.setdefault('SenDetMasterTool', result.getPublicTool("SensitiveDetectorMasterTool")) #NOTE - is still a public tool
+    #
+    #Write MetaData container
+    #
+    #result.merge(writeSimulationParametersMetadata(ConfigFlags))
+    #
+    #User action services (Slow...)
+    #
+    result.merge(UserActionMaterialStepRecorderSvcCfg(ConfigFlags) )
+    kwargs.setdefault('UserActionSvc', result.getService( "G4UA::UserActionSvc") )
+
+    #PhysicsListSvc
+    result.merge( PhysicsListSvcCfg(ConfigFlags) )
+    kwargs.setdefault('PhysicsListSvc', result.getService( "PhysicsListSvc") )
+
+    #
+    #  Output level
+    #
+    ## G4AtlasAlg verbosities (available domains = Navigator, Propagator, Tracking, Stepping, Stacking, Event)
+    ## Set stepper verbose = 1 if the Athena logging level is <= DEBUG
+    # TODO: Why does it complain that G4AtlasAlgConf.G4AtlasAlg has no "Verbosities" object? Fix.
+    verbosities=dict(Placeholder = '0')
+    if "OutputLevel" in kwargs and kwargs["OutputLevel"] <= 2 :
+       verbosities["Tracking"]='1'
+       print (verbosities)
+    kwargs.setdefault('Verbosities', verbosities)
+    #
+    # Set commands for the G4FaserAlg
+    #
+    kwargs.setdefault("G4Commands", ConfigFlags.Sim.G4Commands)
+
+    result.addEventAlgo(G4FaserAlg(name, **kwargs))
+    return result
+
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py b/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a35c670ec1b4c4b58bf0769b827a9df69a04cd5
--- /dev/null
+++ b/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+if __name__ == "__main__":
+    import os
+    import sys
+    import GaudiPython
+    import ParticleGun as PG
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    from AthenaConfiguration.ComponentFactory import CompFactory
+    from AthenaCommon.AppMgr import *
+    from AthenaCommon.Logging import log, logging
+    from AthenaCommon.SystemOfUnits import TeV
+    from AthenaCommon.PhysicalConstants import pi
+    from AthenaCommon.Constants import VERBOSE, INFO
+    from AthenaCommon.Configurable import Configurable
+    from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+    from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+    from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+    from McEventSelector.McEventSelectorConfig import McEventSelectorCfg
+    from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+    from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+    from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg
+    from G4FaserAlg.G4FaserAlgConfigNew import G4FaserMaterialStepRecorderAlgCfg
+    from G4FaserServices.G4FaserServicesConfigNew import G4GeometryNotifierSvcCfg
+#
+# Set up logging and new style config
+#
+    log.setLevel(VERBOSE)
+    Configurable.configurableRun3Behavior = True
+#
+# Input settings (Generator file)
+#
+#   from AthenaConfiguration.TestDefaults import defaultTestFiles
+#   ConfigFlags.Input.Files = defaultTestFiles.EVNT
+#
+# Alternatively, these must ALL be explicitly set to run without an input file
+# (if missing, it will try to read metadata from a non-existent file and crash)
+#
+    ConfigFlags.Input.Files = [""]
+    ConfigFlags.Input.isMC = True
+    ConfigFlags.Input.RunNumber = 12345
+    ConfigFlags.Input.Collections = [""]
+    ConfigFlags.Input.ProjectName = "mc19"
+    ConfigFlags.Common.isOnline = False
+    ConfigFlags.Beam.Type = "collisions"
+    ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
+    ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+# Workaround for bug/missing flag; unimportant otherwise 
+    ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
+# Workaround to avoid problematic ISF code
+    ConfigFlags.GeoModel.Layout = "Development"
+#
+# Output settings
+#
+    ConfigFlags.Output.HITSFileName = "MaterialStepCollection.root"
+    ConfigFlags.GeoModel.GeoExportFile = "faserGeo.db" # Optional dump of geometry for browsing in vp1light
+#
+# Geometry-related settings
+# Do not change!
+#
+    ConfigFlags.Detector.SimulateVeto   = True
+    ConfigFlags.Detector.GeometryVeto   = True
+    ConfigFlags.Detector.SimulateTrigger= True
+    ConfigFlags.Detector.GeometryTrigger= True
+    ConfigFlags.Detector.SimulatePreshower   = True
+    ConfigFlags.Detector.GeometryPreshower   = True
+    ConfigFlags.Detector.SimulateFaserSCT   = True
+    ConfigFlags.Detector.GeometryFaserSCT   = True
+    ConfigFlags.Detector.SimulateUpstreamDipole = True
+    ConfigFlags.Detector.SimulateCentralDipole = True
+    ConfigFlags.Detector.SimulateDownstreamDipole = True
+    ConfigFlags.Detector.GeometryUpstreamDipole = True
+    ConfigFlags.Detector.GeometryCentralDipole = True
+    ConfigFlags.Detector.GeometryDownstreamDipole = True
+    ConfigFlags.GeoModel.Align.Dynamic  = False
+    ConfigFlags.Sim.ReleaseGeoModel     = False
+#
+# All flags should be set before calling lock
+#
+    ConfigFlags.lock()
+#
+# Construct ComponentAccumulator
+#
+    acc = MainServicesCfg(ConfigFlags)
+#
+# Particle Gun generator (comment out to read generator file)
+# Raw energies (without units given) are interpreted as MeV
+#
+    pg = PG.ParticleGun()
+    pg.McEventKey = "GEN_EVENT"
+    pg.randomSeed = 123456
+    pg.sampler.pid = 999
+    pg.sampler.mom = PG.EThetaMPhiSampler(energy=1*TeV, theta=[0, pi/20], phi=[0, 2*pi])
+    pg.sampler.pos = PG.PosSampler(x=[-5, 5], y=[-5, 5], z=-2100.0, t=0.0)
+    acc.addEventAlgo(pg, "AthBeginSeq") # to run *before* G4
+#
+# Only one of these two should be used in a given job
+# (MCEventSelectorCfg for generating events with no input file,
+#  PoolReadCfg when reading generator data from an input file)
+#    
+    acc.merge(McEventSelectorCfg(ConfigFlags))
+    # acc.merge(PoolReadCfg(ConfigFlags))
+#
+#  Output stream configuration
+#
+    acc.merge(OutputStreamCfg(ConfigFlags, 
+                              "HITS", 
+                             ["EventInfo#*",
+                              "McEventCollection#TruthEvent",
+                              "McEventCollection#GEN_EVENT",
+			      "Trk::MaterialStepCollection#*",
+                              "ScintHitCollection#*",
+                              "FaserSiHitCollection#*"
+                            ], disableEventTag=True))
+    acc.getEventAlgo("OutputStreamHITS").AcceptAlgs = ["G4FaserAlg"]               # optional
+    acc.getEventAlgo("OutputStreamHITS").WritingTool.ProcessingTag = "StreamHITS"  # required
+#
+#  Here is the configuration of the Geant4 pieces
+#    
+    acc.merge(FaserGeometryCfg(ConfigFlags))
+    acc.merge(G4FaserMaterialStepRecorderAlgCfg(ConfigFlags))
+    acc.addService(G4GeometryNotifierSvcCfg(ConfigFlags, ActivateLVNotifier=True))
+#
+# Verbosity
+#
+#    ConfigFlags.dump()
+#    logging.getLogger('forcomps').setLevel(VERBOSE)
+#    acc.foreach_component("*").OutputLevel = VERBOSE
+#    acc.foreach_component("*ClassID*").OutputLevel = INFO
+#    acc.getService("StoreGateSvc").Dump=True
+#    acc.getService("ConditionStore").Dump=True
+#    acc.printConfig()
+    f=open('FaserG4AppCfg_EVNT.pkl','wb')
+    acc.store(f)
+    f.close()
+#
+# Execute and finish
+#
+    sys.exit(int(acc.run(maxEvents=20000).isFailure()))
diff --git a/Simulation/G4Faser/G4FaserServices/python/G4FaserUserActionConfigNew.py b/Simulation/G4Faser/G4FaserServices/python/G4FaserUserActionConfigNew.py
index 3c54dd5db871f7c19f004d3b9e803a509e798500..588c6f6d411b813b3c86842de68d22aceb858928 100644
--- a/Simulation/G4Faser/G4FaserServices/python/G4FaserUserActionConfigNew.py
+++ b/Simulation/G4Faser/G4FaserServices/python/G4FaserUserActionConfigNew.py
@@ -6,7 +6,7 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 
 G4UA__UserActionSvc=CompFactory.G4UA.UserActionSvc
 
-from G4UserActions.G4UserActionsConfigNew import AthenaStackingActionToolCfg, AthenaTrackingActionToolCfg
+from G4UserActions.G4UserActionsConfigNew import AthenaStackingActionToolCfg, AthenaTrackingActionToolCfg, AthenaMaterialStepRecorderToolCfg
 
 
 # New function for all user action types
@@ -60,6 +60,40 @@ def getDefaultActions(ConfigFlags):
 
     return actions
 
+# add MaterialStepRecorderTool for Geantino scan and MaterialMapping
+def getMaterialStepRecorderActions(ConfigFlags):
+    result = ComponentAccumulator()
+
+    actions = []
+
+    actions += [result.popToolsAndMerge( AthenaStackingActionToolCfg(ConfigFlags)  )]
+
+    actions += [result.popToolsAndMerge( AthenaMaterialStepRecorderToolCfg(ConfigFlags)  )]
+    
+    actions += [result.popToolsAndMerge( AthenaTrackingActionToolCfg(ConfigFlags) )]
+
+    return actions
+
+def UserActionMaterialStepRecorderSvcCfg(ConfigFlags, name="G4UA::UserActionSvc", **kwargs):
+    """
+    Get the standard UA svc configurable with all default actions added.
+    This function is normally called by the configured factory, not users.
+    """
+    result = ComponentAccumulator()
+
+    #how to convert this flag?
+    # from G4AtlasApps.SimFlags import simFlags
+    # optActions = simFlags.OptionalUserActionList.get_Value()
+    # new user action tools
+    kwargs.setdefault('UserActionTools',
+                      getMaterialStepRecorderActions(ConfigFlags))
+
+    # placeholder for more advanced config, if needed
+    result.addService ( G4UA__UserActionSvc(name, **kwargs) )
+
+    return result
+    
+
 def UserActionSvcCfg(ConfigFlags, name="G4UA::UserActionSvc", **kwargs):
     """
     Get the standard UA svc configurable with all default actions added.
diff --git a/Simulation/G4Utilities/G4UserActions/python/G4UserActionsConfigNew.py b/Simulation/G4Utilities/G4UserActions/python/G4UserActionsConfigNew.py
index 4f37ffb40ce67bc563cc4898660e42b414691379..ecac4c267d074dc6326b14275f4096eab7e7898b 100644
--- a/Simulation/G4Utilities/G4UserActions/python/G4UserActionsConfigNew.py
+++ b/Simulation/G4Utilities/G4UserActions/python/G4UserActionsConfigNew.py
@@ -4,6 +4,7 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
 G4UA__AthenaStackingActionTool=CompFactory.G4UA.AthenaStackingActionTool
 G4UA__AthenaTrackingActionTool=CompFactory.G4UA.AthenaTrackingActionTool
+G4UA__AthenaMaterialStepRecorderTool=CompFactory.G4UA.MaterialStepRecorderTool
 
 # this is a bit cumbersome, but it seems ike it is a lot easier to separate
 # the getter functionality from all the rest (i.e. adding the action).
@@ -53,3 +54,9 @@ def AthenaTrackingActionToolCfg(ConfigFlags, name='G4UA::AthenaTrackingActionToo
     kwargs.setdefault('SubDetVolumeLevel', subDetLevel)
     result.setPrivateTools( G4UA__AthenaTrackingActionTool(name,**kwargs) )
     return result
+
+def AthenaMaterialStepRecorderToolCfg(ConfigFlags, name='G4UA::MaterialStepRecorderTool', **kwargs):
+    result = ComponentAccumulator()
+
+    result.setPrivateTools( G4UA__AthenaMaterialStepRecorderTool(name,**kwargs) )
+    return result
diff --git a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
index 260732e2f948613aecae732b06a03fc6a9a1ef6e..28b8c22ea0ff95f5f150c1e0b7c92eedb05c6dd0 100755
--- a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
@@ -6,26 +6,30 @@ atlas_subdir( FaserActsGeometry )
 find_package( CLHEP )
 find_package( Eigen )
 find_package( Boost )
+find_package( nlohmann_json )
 
 find_package( Acts COMPONENTS Core )
 
 atlas_add_library( FaserActsGeometryLib 
-		   FaserActsGeometry/FaserActsGeometryContext.h
-		   FaserActsGeometry/FaserActsDetectorElement.h
+			 src/FaserActsSurfaceMappingTool.cxx
+			 src/FaserActsMaterialMapping.cxx
 		   src/FaserActsAlignmentStore.cxx
 		   src/FaserActsDetectorElement.cxx
 		   src/FaserActsLayerBuilder.cxx
 		   src/CuboidVolumeBuilder.cxx
+			 src/FaserActsJsonGeometryConverter.cxx
 		   src/util/*.cxx
 		   PUBLIC_HEADERS FaserActsGeometry
 		   INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS}
-		   LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${BOOST_LIBRARIES}
+		   LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json
 	       	   TrackerIdentifier 
 		   TrackerReadoutGeometry
 		   ActsInteropLib
 		   FaserActsGeometryInterfacesLib
 		   AthenaKernel												                         
 		   ActsCore
+			 ActsGeometryLib
+			 ActsGeometryInterfacesLib
 		   MagFieldInterfaces 
 		   MagFieldElements 
 		   MagFieldConditions
@@ -37,12 +41,17 @@ atlas_add_library( FaserActsGeometryLib
 		   TrackerIdentifier 
 		   TrackerPrepRawData
 		   TrkSpacePoint
+			 TrkGeometry
 		  )
 
 
 # Component(s) in the package:
 atlas_add_component( FaserActsGeometry
 ##src/*.cxx
+			   src/FaserActsSurfaceMappingTool.cxx
+				 src/FaserActsMaterialMapping.cxx
+				 src/FaserActsMaterialJsonWriterTool.cxx
+				 src/FaserActsJsonGeometryConverter.cxx
 		     src/FaserActsTrackingGeometrySvc.cxx
 		     src/FaserActsTrackingGeometryTool.cxx
                      src/FaserActsWriteTrackingGeometry.cxx
@@ -53,6 +62,7 @@ atlas_add_component( FaserActsGeometry
 		     src/FaserActsAlignmentCondAlg.cxx
 		     src/NominalAlignmentCondAlg.cxx
 #src/FaserActsKalmanFilterAlg.cxx
+                     src/FaserActsVolumeMappingTool.cxx
 		     src/components/*.cxx
                      PUBLIC_HEADERS FaserActsGeometry
                      INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS}
@@ -64,6 +74,8 @@ atlas_add_component( FaserActsGeometry
 		     ActsInteropLib
 		     FaserActsGeometryInterfacesLib
                      ActsCore
+										 ActsGeometryLib
+										 ActsGeometryInterfacesLib
                      MagFieldInterfaces
                      MagFieldElements
                      MagFieldConditions
@@ -75,6 +87,7 @@ atlas_add_component( FaserActsGeometry
 	   	     TrackerIdentifier 
 	   	     TrackerPrepRawData
 	   	     TrkSpacePoint
+					TrkGeometry
 
 	 	   )
 
diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsJsonGeometryConverter.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsJsonGeometryConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..2936c9d327beb61033ab4a975d2386e1fd7ee5eb
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsJsonGeometryConverter.h
@@ -0,0 +1,261 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 CERN for the benefit of the Acts project
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
+#include "Acts/Material/MaterialSlab.hpp"
+#include "Acts/Utilities/BinUtility.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/Logger.hpp"
+#include <Acts/Geometry/TrackingVolume.hpp>
+#include <Acts/Surfaces/Surface.hpp>
+
+#include <map>
+
+#include <nlohmann/json.hpp>
+
+namespace Acts {
+
+/// @class FaserActsJsonGeometryConverter
+///
+/// @brief read the material from Json
+class FaserActsJsonGeometryConverter {
+ public:
+  using SurfaceMaterialMap =
+      std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>;
+
+  using VolumeMaterialMap =
+      std::map<GeometryIdentifier, std::shared_ptr<const IVolumeMaterial>>;
+
+  using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
+
+  using geo_id_value = uint64_t;
+
+  using SurfaceMaterialRep = std::map<geo_id_value, const ISurfaceMaterial*>;
+  using SurfaceRep = std::map<geo_id_value, const Surface*>;
+  using VolumeMaterialRep = std::map<geo_id_value, const IVolumeMaterial*>;
+
+  /// @brief Layer representation for Json writing
+  struct LayerRep {
+    // the layer id
+    GeometryIdentifier layerID;
+
+    SurfaceMaterialRep sensitives;
+    SurfaceRep sensitiveSurfaces;
+    SurfaceMaterialRep approaches;
+    SurfaceRep approacheSurfaces;
+    const ISurfaceMaterial* representing = nullptr;
+    const Surface* representingSurface = nullptr;
+
+    /// The LayerRep is actually worth it to write out
+    operator bool() const {
+      return (!sensitives.empty() or !approaches.empty() or
+              representing != nullptr);
+    }
+  };
+
+  /// @brief Volume representation for Json writing
+  struct VolumeRep {
+    // The geometry id
+    GeometryIdentifier volumeID;
+
+    /// The namne
+    std::string volumeName;
+
+    std::map<geo_id_value, LayerRep> layers;
+    SurfaceMaterialRep boundaries;
+    SurfaceRep boundarySurfaces;
+    const IVolumeMaterial* material = nullptr;
+
+    /// The VolumeRep is actually worth it to write out
+    operator bool() const {
+      return (!layers.empty() or !boundaries.empty() or material != nullptr);
+    }
+  };
+
+  /// @brief Detector representation for Json writing
+  struct DetectorRep {
+    std::map<geo_id_value, VolumeRep> volumes;
+  };
+
+  /// @class Config
+  /// Configuration of the Reader
+  class Config {
+   public:
+    /// The geometry version
+    std::string geoversion = "undefined";
+    /// The detector tag
+    std::string detkey = "detector";
+    /// The volume identification string
+    std::string volkey = "volumes";
+    /// The name identification
+    std::string namekey = "Name";
+    /// The boundary surface string
+    std::string boukey = "boundaries";
+    /// The layer identification string
+    std::string laykey = "layers";
+    /// The volume material string
+    std::string matkey = "material";
+    /// The approach identification string
+    std::string appkey = "approach";
+    /// The sensitive identification string
+    std::string senkey = "sensitive";
+    /// The representing idntification string
+    std::string repkey = "representing";
+    /// The bin keys
+    std::string bin0key = "bin0";
+    /// The bin1 key
+    std::string bin1key = "bin1";
+    /// The bin2 key
+    std::string bin2key = "bin2";
+    /// The local to global tranfo key
+    std::string transfokeys = "tranformation";
+    /// The type key -> proto, else
+    std::string typekey = "type";
+    /// The data key
+    std::string datakey = "data";
+    /// The geoid key
+    std::string geometryidkey = "Geoid";
+    /// The surface geoid key
+    std::string surfacegeometryidkey = "SGeoid";
+    /// The mapping key, add surface to map if true
+    std::string mapkey = "mapMaterial";
+    /// The surface type key
+    std::string surfacetypekey = "stype";
+    /// The surface position key
+    std::string surfacepositionkey = "sposition";
+    /// The surface range key
+    std::string surfacerangekey = "srange";
+    /// The default logger
+    std::shared_ptr<const Logger> logger;
+    /// The name of the writer
+    std::string name = "";
+
+    /// Steering to handle sensitive data
+    bool processSensitives = true;
+    /// Steering to handle approach data
+    bool processApproaches = true;
+    /// Steering to handle representing data
+    bool processRepresenting = true;
+    /// Steering to handle boundary data
+    bool processBoundaries = true;
+    /// Steering to handle volume data
+    bool processVolumes = true;
+    /// Steering to handle volume data
+    bool processDenseVolumes = false;
+    /// Add proto material to all surfaces
+    bool processnonmaterial = false;
+    /// Write out data
+    bool writeData = true;
+
+    /// Constructor
+    ///
+    /// @param lname Name of the writer tool
+    /// @param lvl The output logging level
+    Config(const std::string& lname = "FaserActsJsonGeometryConverter",
+           Logging::Level lvl = Logging::INFO)
+        : logger(getDefaultLogger(lname, lvl)), name(lname) {}
+  };
+
+  /// Constructor
+  ///
+  /// @param cfg configuration struct for the reader
+  FaserActsJsonGeometryConverter(const Config& cfg);
+
+  /// Destructor
+  ~FaserActsJsonGeometryConverter() = default;
+
+  /// Convert method
+  ///
+  /// @param surfaceMaterialMap The indexed material map collection
+  std::pair<
+      std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>,
+      std::map<GeometryIdentifier, std::shared_ptr<const IVolumeMaterial>>>
+  jsonToMaterialMaps(const nlohmann::json& materialmaps);
+
+  /// Convert method
+  ///
+  /// @param surfaceMaterialMap The indexed material map collection
+  nlohmann::json materialMapsToJson(const DetectorMaterialMaps& maps);
+
+  /// Write method
+  ///
+  /// @param tGeometry is the tracking geometry which contains the material
+  nlohmann::json trackingGeometryToJson(const TrackingGeometry& tGeometry);
+
+ private:
+  /// Convert to internal representation method, recursive call
+  ///
+  /// @param tGeometry is the tracking geometry which contains the material
+  void convertToRep(DetectorRep& detRep, const TrackingVolume& tVolume);
+
+  /// Convert to internal representation method
+  ///
+  /// @param tGeometry is the tracking geometry which contains the material
+  LayerRep convertToRep(const Layer& tLayer);
+
+  /// Create the Surface Material from Json
+  /// - factory method, ownership given
+  /// @param material is the json part representing a material object
+  const ISurfaceMaterial* jsonToSurfaceMaterial(const nlohmann::json& material);
+
+  /// Create the Volume Material from Json
+  /// - factory method, ownership given
+  /// @param material is the json part representing a material object
+  const IVolumeMaterial* jsonToVolumeMaterial(const nlohmann::json& material);
+
+  /// Create the Material Matrix from Json
+  ///
+  /// @param data is the json part representing a material data array
+  MaterialSlabMatrix jsonToMaterialMatrix(const nlohmann::json& data);
+
+  /// Create the BinUtility for from Json
+  BinUtility jsonToBinUtility(const nlohmann::json& bin);
+
+  /// Create the local to global transform for from Json
+  Transform3D jsonToTransform(const nlohmann::json& transfo);
+
+  /// Create Json from a detector represenation
+  nlohmann::json detectorRepToJson(const DetectorRep& detRep);
+
+  /// SurfaceMaterial to Json
+  ///
+  /// @param the SurfaceMaterial
+  nlohmann::json surfaceMaterialToJson(const ISurfaceMaterial& sMaterial);
+
+  /// VolumeMaterial to Json
+  ///
+  /// @param the VolumeMaterial
+  nlohmann::json volumeMaterialToJson(const IVolumeMaterial& vMaterial);
+
+  /// Add surface information to json surface
+  ///
+  /// @param The json surface The surface
+  void addSurfaceToJson(nlohmann::json& sjson, const Surface* surface);
+
+  /// Default BinUtility to create proto material
+  ///
+  /// @param the Surface
+  Acts::BinUtility DefaultBin(const Acts::Surface& surface);
+
+  /// Default BinUtility to create proto material
+  ///
+  /// @param the Volume
+  Acts::BinUtility DefaultBin(const Acts::TrackingVolume& volume);
+
+  /// The config class
+  Config m_cfg;
+
+  /// Private access to the logging instance
+  const Logger& logger() const { return *m_cfg.logger; }
+};
+
+}  // namespace Acts
diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialJsonWriterTool.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialJsonWriterTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3959e307137f5b49633a48f753b57d9d308e554
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialJsonWriterTool.h
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ACTSGEOMETRY_FASERACTSMATERIALJSONWRITERTOOL_H
+#define ACTSGEOMETRY_FASERACTSMATERIALJSONWRITERTOOL_H
+
+// ATHENA
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "AthenaBaseComps/AthService.h"
+#include "GaudiKernel/IInterface.h"
+#include "Gaudi/Property.h"  /*no forward decl: typedef*/
+
+// PACKAGE
+#include "FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h"
+
+// ACTS
+#include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/Plugins/Json/JsonGeometryConverter.hpp"
+#include "FaserActsGeometry/FaserActsJsonGeometryConverter.h"
+
+namespace Acts {
+  class TrackingGeometry;
+}
+
+class FaserActsMaterialJsonWriterTool : public extends<AthAlgTool, IFaserActsMaterialJsonWriterTool>
+{
+
+public:
+
+  virtual StatusCode initialize() override;
+
+  FaserActsMaterialJsonWriterTool(const std::string& type, const std::string& name,
+                                const IInterface* parent);
+  virtual ~FaserActsMaterialJsonWriterTool() = default;
+
+  virtual
+  void
+  write(const Acts::FaserActsJsonGeometryConverter::DetectorMaterialMaps& detMaterial) const override;
+
+  virtual
+  void
+  write(const Acts::TrackingGeometry& tGeometry) const override;
+
+
+private:
+
+Acts::FaserActsJsonGeometryConverter::Config m_cfg;
+
+  Gaudi::Property<std::string> m_filePath{this, "OutputFile", "material-maps.json", "Output json file for the Material Map"};
+  Gaudi::Property<bool> m_processSensitives{this, "processSensitives", true, "Write sensitive surface to the json file"};
+  Gaudi::Property<bool> m_processApproaches{this, "processApproaches", true, "Write approche surface to the json file"};
+  Gaudi::Property<bool> m_processRepresenting{this, "processRepresenting", true, "Write representing surface to the json file"};
+  Gaudi::Property<bool> m_processBoundaries{this, "processBoundaries", true, "Write boundary surface to the json file"};
+  Gaudi::Property<bool> m_processVolumes{this, "processVolumes", true, "Write volume to the json file"};
+  Gaudi::Property<bool> m_processDenseVolumes{this, "processDenseVolumes", false, "Write dense volume to the json file"};
+  Gaudi::Property<bool> m_processnonmaterial{this, "processnonmaterial", false, "Add proto material to all surfaces and volumes"};
+};
+
+#endif
diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialMapping.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialMapping.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdeb9a7b010b652b13ccaf7fd9986755e8dac8eb
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialMapping.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ACTSMATERIALMAPPING_H
+#define ACTSMATERIALMAPPING_H
+
+// ATHENA
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "Gaudi/Property.h"  /*no forward decl: typedef*/
+#include "GaudiKernel/ISvcLocator.h"
+#include "StoreGate/ReadHandleKey.h"
+#include "TrkGeometry/MaterialStepCollection.h"
+
+// ACTS
+#include "Acts/EventData/TrackParameters.hpp"
+#include "Acts/Geometry/GeometryIdentifier.hpp"
+#include "Acts/Utilities/Helpers.hpp"
+#include "Acts/Material/SurfaceMaterialMapper.hpp"
+#include "Acts/Material/VolumeMaterialMapper.hpp"
+// PACKAGE
+#include "ActsGeometryInterfaces/IActsMaterialTrackWriterSvc.h"
+#include "ActsGeometryInterfaces/IActsMaterialStepConverterTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsSurfaceMappingTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsVolumeMappingTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+
+// STL
+#include <memory>
+#include <vector>
+#include <fstream>
+#include <mutex>
+
+namespace Acts {
+  class ISurfaceMaterial;
+  class IVolumeMaterial;
+
+  using SurfaceMaterialMap
+      = std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>;
+
+  using VolumeMaterialMap
+      = std::map<GeometryIdentifier, std::shared_ptr<const IVolumeMaterial>>;
+
+  using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
+}
+
+
+class FaserActsMaterialMapping : public AthReentrantAlgorithm {
+public:
+  FaserActsMaterialMapping (const std::string& name, ISvcLocator* pSvcLocator);
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+
+private:
+  ServiceHandle<IActsMaterialTrackWriterSvc>      m_materialTrackWriterSvc;
+  Gaudi::Property<bool>                           m_mapSurfaces{this, "mapSurfaces", true, "Map the material onto surfaces"};
+  Gaudi::Property<bool>                           m_mapVolumes{this, "mapVolumes", true, "Map the material onto volumes"};
+  ToolHandle<IActsMaterialStepConverterTool>      m_materialStepConverterTool{this, "MaterialStepConverterTool", "ActsMaterialStepConverterTool"};
+  SG::ReadHandleKey<Trk::MaterialStepCollection>  m_inputMaterialStepCollection;
+  ToolHandle<IFaserActsSurfaceMappingTool>        m_surfaceMappingTool{this, "SurfaceMappingTool", "FaserActsSurfaceMappingTool"};
+  ToolHandle<IFaserActsVolumeMappingTool>         m_volumeMappingTool{this, "VolumeMappingTool", "FaserActsVolumeMappingTool"};
+  ToolHandle<IFaserActsMaterialJsonWriterTool>    m_materialJsonWriterTool{this, "MaterialJsonWriterTool", "FaserActsMaterialJsonWriterTool"};
+
+  Acts::MagneticFieldContext                      m_mctx;
+  Acts::GeometryContext                           m_gctx;
+  Acts::SurfaceMaterialMapper::State              m_mappingState;
+  Acts::VolumeMaterialMapper::State               m_mappingStateVol;
+};
+
+#endif // ActsGeometry_ActsExtrapolation_h
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsSurfaceMappingTool.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsSurfaceMappingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..6dab48486bb6371d1198671c35fa2ca6b5a70225
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsSurfaceMappingTool.h
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERACTSGEOMETRY_FASERACTSSURFACEMAPPINGTOOL_H
+#define FASERACTSGEOMETRY_FASERACTSSURFACEMAPPINGTOOL_H
+
+// ATHENA
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "Gaudi/Property.h"
+#include "GaudiKernel/EventContext.h"
+
+// PACKAGE
+#include "FaserActsGeometryInterfaces/IFaserActsSurfaceMappingTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+
+
+// ACTS
+#include "Acts/Material/SurfaceMaterialMapper.hpp"
+
+// BOOST
+#include <cmath>
+
+class FaserActsSurfaceMappingTool : public extends<AthAlgTool, IFaserActsSurfaceMappingTool>
+{
+
+public:
+  virtual StatusCode initialize() override;
+
+  FaserActsSurfaceMappingTool(const std::string& type, const std::string& name,
+	           const IInterface* parent);
+
+  virtual
+  std::shared_ptr<Acts::SurfaceMaterialMapper>
+  mapper() const override
+  {
+    return m_mapper;
+  };
+
+  virtual
+  Acts::SurfaceMaterialMapper::State
+  mappingState() const override;
+
+  virtual
+  const IFaserActsTrackingGeometryTool*
+  trackingGeometryTool() const override
+  {
+    return m_trackingGeometryTool.get();
+  }
+
+
+private:
+  // Straight line stepper
+  Acts::MagneticFieldContext m_magFieldContext;
+  Acts::GeometryContext      m_geoContext;
+  using SlStepper  = Acts::StraightLineStepper;
+  using StraightLinePropagator = Acts::Propagator<SlStepper, Acts::Navigator>;
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
+  std::shared_ptr<Acts::SurfaceMaterialMapper> m_mapper;
+  std::shared_ptr<const Acts::TrackingGeometry> m_trackingGeometry;
+};
+
+#endif
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsVolumeMappingTool.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsVolumeMappingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..699509d3b19a6ded125222d6fab93a58cadf9dd0
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsVolumeMappingTool.h
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ACTSGEOMETRY_ACTSVOLUMEMAPPINGTOOL_H
+#define ACTSGEOMETRY_ACTSVOLUMEMAPPINGTOOL_H
+
+// ATHENA
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "Gaudi/Property.h"
+#include "GaudiKernel/EventContext.h"
+
+// PACKAGE
+#include "FaserActsGeometryInterfaces/IFaserActsVolumeMappingTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+
+// ACTS
+#include "Acts/Material/VolumeMaterialMapper.hpp"
+
+// BOOST
+
+#include <cmath>
+
+class FaserActsVolumeMappingTool : public extends<AthAlgTool, IFaserActsVolumeMappingTool>
+{
+
+public:
+  virtual StatusCode initialize() override;
+
+  FaserActsVolumeMappingTool(const std::string& type, const std::string& name,
+	           const IInterface* parent);
+
+  std::shared_ptr<Acts::VolumeMaterialMapper>
+  mapper() const override
+  {
+    return m_mapper;
+  };
+
+  virtual
+  Acts::VolumeMaterialMapper::State
+  mappingState() const override;
+
+  virtual
+  const IFaserActsTrackingGeometryTool*
+  trackingGeometryTool() const override
+  {
+    return m_trackingGeometryTool.get();
+  }
+
+
+private:
+  // Straight line stepper
+  Acts::MagneticFieldContext m_magFieldContext;
+  Acts::GeometryContext      m_geoContext;
+  using SlStepper  = Acts::StraightLineStepper;
+  using StraightLinePropagator = Acts::Propagator<SlStepper, Acts::Navigator>;
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", "ActsTrackingGeometryTool"};
+  std::shared_ptr<Acts::VolumeMaterialMapper> m_mapper;
+  std::shared_ptr<const Acts::TrackingGeometry> m_trackingGeometry;
+};
+
+
+
+#endif
diff --git a/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py b/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..84bfe224aad7f984ffa7ca1f712a2db5525e7427
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py
@@ -0,0 +1,166 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator 
+from AthenaConfiguration.ComponentFactory import CompFactory
+FaserActsWriteTrackingGeometry,FaserActsTrackingGeometrySvc,FaserActsTrackingGeometryTool,FaserActsSurfaceMappingTool,FaserActsVolumeMappingTool,FaserActsObjWriterTool,FaserActsAlignmentCondAlg = CompFactory.getComps("FaserActsWriteTrackingGeometry","FaserActsTrackingGeometrySvc","FaserActsTrackingGeometryTool","FaserActsSurfaceMappingTool","FaserActsVolumeMappingTool","FaserActsObjWriterTool","FaserActsAlignmentCondAlg")
+
+
+
+def ActsTrackingGeometrySvcCfg(configFlags, name = "ActsTrackingGeometrySvc" ) :
+  result = ComponentAccumulator()
+  actsTrackingGeometrySvc = FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)
+
+  if configFlags.TrackingGeometry.MaterialSource == "Input":
+    actsTrackingGeometrySvc.UseMaterialMap = True
+    actsTrackingGeometrySvc.MaterialMapInputFile = "material-maps.json"
+  if configFlags.TrackingGeometry.MaterialSource.find(".json") != -1:  
+    actsTrackingGeometrySvc.UseMaterialMap = True
+    actsTrackingGeometrySvc.MaterialMapInputFile = configFlags.TrackingGeometry.MaterialSource
+  result.addService(actsTrackingGeometrySvc)
+  return result
+
+def ActsPropStepRootWriterSvcCfg(configFlags, 
+                                 name="ActsPropStepRootWriterSvc",
+                                 FilePath="propsteps.root",
+                                 TreeName="propsteps"):
+    result = ComponentAccumulator()
+
+    ActsPropStepRootWriterSvc = CompFactory.ActsPropStepRootWriterSvc
+    svc = ActsPropStepRootWriterSvc(name=name, 
+                                    FilePath=FilePath, 
+                                    TreeName=TreeName)
+
+    result.addService(svc)
+
+    return result
+
+def ActsTrackingGeometryToolCfg(configFlags, name = "ActsTrackingGeometryTool" ) :
+  result = ComponentAccumulator()
+  from FaserActsGeometry.FaserActsWriteTrackingGeometryConfig import FaserActsTrackingGeometrySvcCfg
+  acc = FaserActsTrackingGeometrySvcCfg(configFlags)
+  result.merge(acc) 
+#  Acts_ActsTrackingGeometryTool = CompFactory.ActsTrackingGeometryTool
+  actsTrackingGeometryTool = FaserActsTrackingGeometryTool("TrackingGeometryTool")
+  result.addPublicTool(actsTrackingGeometryTool)
+  
+  return result, actsTrackingGeometryTool
+
+def NominalAlignmentCondAlgCfg(configFlags, name = "NominalAlignmentCondAlg", **kwargs) :
+  result = ComponentAccumulator()
+  
+  acc = ActsTrackingGeometrySvcCfg(configFlags)
+  result.merge(acc)
+  
+  Acts_NominalAlignmentCondAlg = CompFactory.NominalAlignmentCondAlg
+  nominalAlignmentCondAlg = Acts_NominalAlignmentCondAlg(name, **kwargs)
+  result.addCondAlgo(nominalAlignmentCondAlg)
+  
+  return result
+
+def ActsAlignmentCondAlgCfg(configFlags, name = "ActsAlignmentCondAlg", **kwargs) :
+  result = ComponentAccumulator()
+  
+  acc = ActsTrackingGeometrySvcCfg(configFlags)
+  result.merge(acc)
+  
+  Acts_ActsAlignmentCondAlg = CompFactory.ActsAlignmentCondAlg
+  actsAlignmentCondAlg = Acts_ActsAlignmentCondAlg(name, **kwargs)
+  result.addCondAlgo(actsAlignmentCondAlg)
+  
+  return result
+
+from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
+def ActsExtrapolationToolCfg(configFlags, name="ActsExtrapolationTool", **kwargs) :
+  result=ComponentAccumulator()
+  
+  acc  = MagneticFieldSvcCfg(configFlags)
+  result.merge(acc)
+  
+  acc, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(configFlags) 
+  result.merge(acc)
+  
+  Acts_ActsExtrapolationTool = CompFactory.ActsExtrapolationTool
+  actsExtrapolationTool = Acts_ActsExtrapolationTool(name, **kwargs)
+  result.addPublicTool(actsExtrapolationTool, primary=True)
+  return result
+
+
+def ActsMaterialTrackWriterSvcCfg(name="ActsMaterialTrackWriterSvc",
+                                  FilePath="MaterialTracks_mapping.root",
+                                  TreeName="material-tracks") :
+  result = ComponentAccumulator()
+
+  Acts_ActsMaterialTrackWriterSvc = CompFactory.ActsMaterialTrackWriterSvc
+  ActsMaterialTrackWriterSvc = Acts_ActsMaterialTrackWriterSvc(name, 
+                                                               FilePath=FilePath,
+                                                               TreeName=TreeName)
+
+  from AthenaCommon.Constants import INFO
+  ActsMaterialTrackWriterSvc.OutputLevel = INFO
+  result.addService(ActsMaterialTrackWriterSvc, primary=True)
+  return result
+
+def ActsMaterialStepConverterToolCfg(name = "ActsMaterialStepConverterTool" ) :
+  result=ComponentAccumulator()
+  
+  Acts_ActsMaterialStepConverterTool = CompFactory.ActsMaterialStepConverterTool
+  ActsMaterialStepConverterTool = Acts_ActsMaterialStepConverterTool(name)
+
+  from AthenaCommon.Constants import INFO
+  ActsMaterialStepConverterTool.OutputLevel = INFO
+
+  result.addPublicTool(ActsMaterialStepConverterTool, primary=True)
+  return result
+
+def ActsSurfaceMappingToolCfg(configFlags, name = "FaserActsSurfaceMappingTool" ) :
+  result=ComponentAccumulator()
+    
+  acc, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(configFlags) 
+  result.merge(acc)
+
+  Acts_ActsSurfaceMappingTool = CompFactory.FaserActsSurfaceMappingTool
+  ActsSurfaceMappingTool = Acts_ActsSurfaceMappingTool(name)
+
+  from AthenaCommon.Constants import INFO
+  ActsSurfaceMappingTool.OutputLevel = INFO
+
+  result.addPublicTool(ActsSurfaceMappingTool, primary=True)
+  return result
+
+def ActsVolumeMappingToolCfg(configFlags, name = "ActsVolumeMappingTool" ) :
+  result=ComponentAccumulator()
+    
+  acc, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(configFlags) 
+  result.merge(acc)
+
+  Acts_ActsVolumeMappingTool = CompFactory.FaserActsVolumeMappingTool
+  FaserActsVolumeMappingTool = Acts_ActsVolumeMappingTool(name)
+
+  from AthenaCommon.Constants import INFO
+  FaserActsVolumeMappingTool.OutputLevel = INFO
+
+  result.addPublicTool(FaserActsVolumeMappingTool, primary=True)
+  return result
+
+def ActsMaterialJsonWriterToolCfg(name= "ActsMaterialJsonWriterTool", **kwargs) :
+  result=ComponentAccumulator()
+    
+  Acts_ActsMaterialJsonWriterTool = CompFactory.ActsMaterialJsonWriterTool
+  ActsMaterialJsonWriterTool = Acts_ActsMaterialJsonWriterTool(name, **kwargs)
+
+  from AthenaCommon.Constants import INFO
+  ActsMaterialJsonWriterTool.OutputLevel = INFO
+
+  result.addPublicTool(ActsMaterialJsonWriterTool, primary=True)
+  return result
+
+def ActsObjWriterToolCfg(name= "ActsObjWriterTool", **kwargs) :
+  result=ComponentAccumulator()
+    
+  Acts_ActsObjWriterTool = CompFactory.ActsObjWriterTool
+  ActsObjWriterTool = Acts_ActsObjWriterTool(name, **kwargs)
+
+  from AthenaCommon.Constants import INFO
+  ActsObjWriterTool.OutputLevel = INFO
+
+  result.addPublicTool(ActsObjWriterTool, primary=True)
+  return result
diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..63f3a60283daceb5133497d58a04067836837830
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py
@@ -0,0 +1,109 @@
+###############################################################
+#
+# Map material from a Geantino scan onto the surfaces and 
+# volumes of the detector to creat a material map.
+#
+###############################################################
+
+
+##########################################################################
+# start from scratch with component accumulator
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+from FaserActsGeometry.ActsGeometryConfig import ActsMaterialStepConverterToolCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsSurfaceMappingToolCfg, ActsVolumeMappingToolCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsMaterialJsonWriterToolCfg
+
+from FaserActsGeometry.ActsGeometryConfig import ActsAlignmentCondAlgCfg
+from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+
+def ActsMaterialMappingCfg(configFlags, name = "FaserActsMaterialMapping", **kwargs):
+  result = ComponentAccumulator()
+
+  MaterialStepConverterTool = ActsMaterialStepConverterToolCfg()
+  kwargs["MaterialStepConverterTool"] = MaterialStepConverterTool.getPrimary()   
+  result.merge(MaterialStepConverterTool)
+
+  ActsSurfaceMappingTool = ActsSurfaceMappingToolCfg(configFlags)
+  kwargs["SurfaceMappingTool"] = ActsSurfaceMappingTool.getPrimary()   
+  result.merge(ActsSurfaceMappingTool)
+
+  FaserActsVolumeMappingTool = ActsVolumeMappingToolCfg(configFlags)
+  kwargs["VolumeMappingTool"] = FaserActsVolumeMappingTool.getPrimary()
+  result.merge(FaserActsVolumeMappingTool)
+
+  ActsMaterialJsonWriterTool = ActsMaterialJsonWriterToolCfg(OutputFile = "material-maps.json",
+                                                            processSensitives = False,
+                                                            processnonmaterial = False)
+                                                            
+  kwargs["MaterialJsonWriterTool"] = ActsMaterialJsonWriterTool.getPrimary()   
+  result.merge(ActsMaterialJsonWriterTool)
+
+  FaserActsMaterialMapping = CompFactory.FaserActsMaterialMapping
+  alg = FaserActsMaterialMapping(name, **kwargs)
+  result.addEventAlgo(alg)
+
+  return result
+
+if "__main__" == __name__:
+  from AthenaCommon.Configurable import Configurable
+  from AthenaCommon.Logging import log
+  from AthenaCommon.Constants import VERBOSE, INFO
+  from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+  from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+  from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+  from FaserActsGeometry.ActsGeometryConfig import ActsMaterialTrackWriterSvcCfg
+  Configurable.configurableRun3Behavior = True
+
+  ## Just enable ID for the moment.
+  ConfigFlags.Input.isMC             = True
+  ConfigFlags.Beam.Type = "collisions" 
+  ConfigFlags.GeoModel.FaserVersion  = "FASER-01"
+  ConfigFlags.IOVDb.GlobalTag        = "OFLCOND-XXXX-XXX-XX"
+#  ConfigFlags.Detector.SimulateBpipe = False
+#  ConfigFlags.Detector.SimulateID    = False
+#  ConfigFlags.Detector.GeometryBpipe = True
+#  ConfigFlags.Detector.GeometryID    = True
+#  ConfigFlags.Detector.GeometryPixel = True
+#  ConfigFlags.Detector.GeometrySCT   = True
+#  ConfigFlags.Detector.GeometryCalo  = True
+#  ConfigFlags.Detector.GeometryMuon  = False
+#  ConfigFlags.Detector.GeometryTRT   = True
+  ConfigFlags.TrackingGeometry.MaterialSource = "geometry-maps.json"
+  ConfigFlags.Concurrency.NumThreads = 1
+  ConfigFlags.Concurrency.NumConcurrentEvents = 1
+
+  ConfigFlags.lock()
+  ConfigFlags.dump()
+
+  cfg = MainServicesCfg(ConfigFlags)
+
+  cfg.merge(FaserGeometryCfg(ConfigFlags))
+  cfg.merge(ActsMaterialTrackWriterSvcCfg("ActsMaterialTrackWriterSvc",
+                                          "MaterialTracks_mapping.root"))
+
+  cfg.merge(PoolReadCfg(ConfigFlags))
+  eventSelector = cfg.getService("EventSelector")
+  eventSelector.InputCollections = ["MaterialStepCollection.root"]
+
+#  from BeamPipeGeoModel.BeamPipeGMConfig import BeamPipeGeometryCfg
+#  cfg.merge(BeamPipeGeometryCfg(ConfigFlags))
+
+#  alignCondAlgCfg = ActsAlignmentCondAlgCfg(ConfigFlags)
+
+#  cfg.merge(alignCondAlgCfg)
+
+  alg = ActsMaterialMappingCfg(ConfigFlags,
+                               OutputLevel=INFO,
+                               mapSurfaces = True,
+                               mapVolumes = True)
+
+  cfg.merge(alg)
+
+  cfg.printConfig()
+
+  log.info("CONFIG DONE")
+
+  cfg.run(80000)
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsJsonGeometryConverter.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsJsonGeometryConverter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1984993b9ce69666daa2a5dc5e78865cd667eee8
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsJsonGeometryConverter.cxx
@@ -0,0 +1,1069 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 CERN for the benefit of the Acts project
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "FaserActsGeometry/FaserActsJsonGeometryConverter.h"
+
+#include "Acts/Geometry/ApproachDescriptor.hpp"
+#include "Acts/Geometry/CuboidVolumeBounds.hpp"
+#include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp"
+#include "Acts/Geometry/CylinderVolumeBounds.hpp"
+#include "Acts/Geometry/GeometryIdentifier.hpp"
+#include "Acts/Geometry/TrackingVolume.hpp"
+#include "Acts/Material/BinnedSurfaceMaterial.hpp"
+#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
+#include "Acts/Material/HomogeneousVolumeMaterial.hpp"
+#include "Acts/Material/InterpolatedMaterialMap.hpp"
+#include "Acts/Material/MaterialGridHelper.hpp"
+#include "Acts/Material/ProtoSurfaceMaterial.hpp"
+#include "Acts/Material/ProtoVolumeMaterial.hpp"
+#include "Acts/Surfaces/RectangleBounds.hpp"
+#include "Acts/Surfaces/SurfaceArray.hpp"
+#include "Acts/Utilities/BinUtility.hpp"
+#include "Acts/Utilities/BinningType.hpp"
+#include <Acts/Surfaces/AnnulusBounds.hpp>
+#include <Acts/Surfaces/CylinderBounds.hpp>
+#include <Acts/Surfaces/RadialBounds.hpp>
+#include <Acts/Surfaces/SurfaceBounds.hpp>
+
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/finder.hpp>
+#include <boost/algorithm/string/iter_find.hpp>
+
+namespace {
+
+using json = nlohmann::json;
+
+// helper functions to encode/decode indefinite material
+//
+// encoded either as `null` for vacuum or to an array of material parameters
+
+json encodeMaterial(const Acts::Material& material) {
+  if (!material) {
+    return nullptr;
+  }
+  json encoded = json::array();
+  for (unsigned i = 0; i < material.parameters().size(); ++i) {
+    encoded.push_back(material.parameters()[i]);
+  }
+  return encoded;
+}
+
+Acts::Material decodeMaterial(const json& encoded) {
+  if (encoded.is_null()) {
+    return {};
+  }
+  Acts::Material::ParametersVector params =
+      Acts::Material::ParametersVector::Zero();
+  for (auto i = params.size(); 0 < i--;) {
+    // .at(...) ensures bound checks
+    params[i] = encoded.at(i);
+  }
+  return Acts::Material(params);
+}
+
+// helper functions to encode/decode concrete material slabs
+//
+// encoded as an object w/ two entries: `material` and `thickness`
+
+json encodeMaterialSlab(const Acts::MaterialSlab& slab) {
+  return {
+      {"material", encodeMaterial(slab.material())},
+      {"thickness", slab.thickness()},
+  };
+}
+
+Acts::MaterialSlab decodeMaterialSlab(const json& encoded) {
+  return Acts::MaterialSlab(decodeMaterial(encoded.at("material")),
+                            encoded.at("thickness").get<float>());
+}
+
+}  // namespace
+
+Acts::FaserActsJsonGeometryConverter::FaserActsJsonGeometryConverter(
+    const Acts::FaserActsJsonGeometryConverter::Config& cfg)
+    : m_cfg(std::move(cfg)) {
+  // Validate the configuration
+  if (!m_cfg.logger) {
+    throw std::invalid_argument("Missing logger");
+  }
+}
+
+std::pair<std::map<Acts::GeometryIdentifier,
+                   std::shared_ptr<const Acts::ISurfaceMaterial>>,
+          std::map<Acts::GeometryIdentifier,
+                   std::shared_ptr<const Acts::IVolumeMaterial>>>
+Acts::FaserActsJsonGeometryConverter::jsonToMaterialMaps(const json& materialmaps) {
+  auto& j = materialmaps;
+  // The return maps
+  std::pair<SurfaceMaterialMap, VolumeMaterialMap> maps;
+  ACTS_VERBOSE("j2a: Reading material maps from json file.");
+  ACTS_VERBOSE("j2a: Found entries for " << j.count(m_cfg.volkey)
+                                         << " volume(s).");
+  // Structured binding
+  for (auto& [key, value] : j.items()) {
+    // Check if this the volume key
+    if (key == m_cfg.volkey) {
+      // Get the volume json
+      auto volj = value;
+      for (auto& [vkey, vvalue] : volj.items()) {
+        // Create the volume id
+        int vid = std::stoi(vkey);
+        Acts::GeometryIdentifier volumeID;
+        volumeID.setVolume(vid);
+        ACTS_VERBOSE("j2a: -> Found Volume " << vid);
+        // Loop through the information in the volume
+        for (auto& [vckey, vcvalue] : vvalue.items()) {
+          if (vckey == m_cfg.boukey and m_cfg.processBoundaries and
+              not vcvalue.empty()) {
+            ACTS_VERBOSE("j2a: --> BoundarySurface(s) to be parsed");
+            for (auto& [bkey, bvalue] : vcvalue.items()) {
+              // Create the boundary id
+              int bid = std::stoi(bkey);
+              Acts::GeometryIdentifier boundaryID(volumeID);
+              boundaryID.setBoundary(bid);
+              ACTS_VERBOSE("j2a: ---> Found boundary surface " << bid);
+              if (bvalue[m_cfg.mapkey] == true) {
+                auto boumat = jsonToSurfaceMaterial(bvalue);
+                maps.first[boundaryID] =
+                    std::shared_ptr<const ISurfaceMaterial>(boumat);
+              }
+            }
+          } else if (vckey == m_cfg.laykey) {
+            ACTS_VERBOSE("j2a: --> Layer(s) to be parsed");
+            // Loop over layers and repeat
+            auto layj = vcvalue;
+            for (auto& [lkey, lvalue] : layj.items()) {
+              // Create the layer id
+              int lid = std::stoi(lkey);
+              Acts::GeometryIdentifier layerID(volumeID);
+              layerID.setLayer(lid);
+              ACTS_VERBOSE("j2a: ---> Found Layer " << lid);
+              // Finally loop over layer components
+              for (auto& [lckey, lcvalue] : lvalue.items()) {
+                if (lckey == m_cfg.repkey and m_cfg.processRepresenting and
+                    not lcvalue.empty()) {
+                  ACTS_VERBOSE("j2a: ----> Found representing surface");
+                  if (lcvalue[m_cfg.mapkey] == true) {
+                    auto repmat = jsonToSurfaceMaterial(lcvalue);
+                    maps.first[layerID] =
+                        std::shared_ptr<const Acts::ISurfaceMaterial>(repmat);
+                  }
+                } else if (lckey == m_cfg.appkey and m_cfg.processApproaches and
+                           not lcvalue.empty()) {
+                  ACTS_VERBOSE("j2a: ----> Found approach surface(s)");
+                  // Loop over approach surfaces
+                  for (auto& [askey, asvalue] : lcvalue.items()) {
+                    // Create the layer id, todo set to max value
+                    int aid = (askey == "*") ? 0 : std::stoi(askey);
+                    Acts::GeometryIdentifier approachID(layerID);
+                    approachID.setApproach(aid);
+                    ACTS_VERBOSE("j2a: -----> Approach surface " << askey);
+                    if (asvalue[m_cfg.mapkey] == true) {
+                      auto appmat = jsonToSurfaceMaterial(asvalue);
+                      maps.first[approachID] =
+                          std::shared_ptr<const Acts::ISurfaceMaterial>(appmat);
+                    }
+                  }
+                } else if (lckey == m_cfg.senkey and m_cfg.processSensitives and
+                           not lcvalue.empty()) {
+                  ACTS_VERBOSE("j2a: ----> Found sensitive surface(s)");
+                  // Loop over sensitive surfaces
+                  for (auto& [sskey, ssvalue] : lcvalue.items()) {
+                    // Create the layer id, todo set to max value
+                    int sid = (sskey == "*") ? 0 : std::stoi(sskey);
+                    Acts::GeometryIdentifier senisitiveID(layerID);
+                    senisitiveID.setSensitive(sid);
+                    ACTS_VERBOSE("j2a: -----> Sensitive surface " << sskey);
+                    if (ssvalue[m_cfg.mapkey] == true) {
+                      auto senmat = jsonToSurfaceMaterial(ssvalue);
+                      maps.first[senisitiveID] =
+                          std::shared_ptr<const Acts::ISurfaceMaterial>(senmat);
+                    }
+                  }
+                }
+              }
+            }
+
+          } else if (m_cfg.processVolumes and vckey == m_cfg.matkey and
+                     not vcvalue.empty()) {
+            ACTS_VERBOSE("--> VolumeMaterial to be parsed");
+            if (vcvalue[m_cfg.mapkey] == true) {
+              auto intermat = jsonToVolumeMaterial(vcvalue);
+              maps.second[volumeID] =
+                  std::shared_ptr<const Acts::IVolumeMaterial>(intermat);
+            }
+          }
+        }
+      }
+    } else if (key == m_cfg.geoversion) {
+      ACTS_VERBOSE("Detector version: " << m_cfg.geoversion);
+    }
+  }
+
+  // Return the filled maps
+  return maps;
+}
+
+/// Convert method
+///
+json Acts::FaserActsJsonGeometryConverter::materialMapsToJson(
+    const DetectorMaterialMaps& maps) {
+  DetectorRep detRep;
+  // Collect all GeometryIdentifiers per VolumeID for the formatted output
+  for (auto& [key, value] : maps.first) {
+    geo_id_value vid = key.volume();
+    auto volRep = detRep.volumes.find(vid);
+    if (volRep == detRep.volumes.end()) {
+      detRep.volumes.insert({vid, VolumeRep()});
+      volRep = detRep.volumes.find(vid);
+      volRep->second.volumeID = key;
+    }
+    geo_id_value lid = key.layer();
+    if (lid != 0) {
+      // we are on a layer, get the layer rep
+      auto layRep = volRep->second.layers.find(lid);
+      if (layRep == volRep->second.layers.end()) {
+        volRep->second.layers.insert({lid, LayerRep()});
+        layRep = volRep->second.layers.find(lid);
+        layRep->second.layerID = key;
+      }
+      // now insert appropriately
+      geo_id_value sid = key.sensitive();
+      geo_id_value aid = key.approach();
+      if (sid != 0) {
+        layRep->second.sensitives.insert({sid, value.get()});
+      } else if (aid != 0) {
+        layRep->second.approaches.insert({aid, value.get()});
+      } else {
+        layRep->second.representing = value.get();
+      }
+
+    } else {
+      // not on a layer can only be a boundary surface
+      geo_id_value bid = key.boundary();
+      volRep->second.boundaries.insert({bid, value.get()});
+    }
+  }
+  for (auto& [key, value] : maps.second) {
+    // find the volume representation
+    geo_id_value vid = key.volume();
+    auto volRep = detRep.volumes.find(vid);
+    if (volRep == detRep.volumes.end()) {
+      detRep.volumes.insert({vid, VolumeRep()});
+      volRep = detRep.volumes.find(vid);
+      volRep->second.volumeID = key;
+    }
+    volRep->second.material = value.get();
+  }
+  // convert the detector representation to json format
+  return detectorRepToJson(detRep);
+}
+
+/// Create Json from a detector represenation
+json Acts::FaserActsJsonGeometryConverter::detectorRepToJson(const DetectorRep& detRep) {
+  json detectorj;
+  ACTS_VERBOSE("a2j: Writing json from detector representation");
+  ACTS_VERBOSE("a2j: Found entries for " << detRep.volumes.size()
+                                         << " volume(s).");
+
+  json volumesj;
+  for (auto& [key, value] : detRep.volumes) {
+    json volj;
+    ACTS_VERBOSE("a2j: -> Writing Volume: " << key);
+    volj[m_cfg.namekey] = value.volumeName;
+    std::ostringstream svolumeID;
+    svolumeID << value.volumeID;
+    volj[m_cfg.geometryidkey] = svolumeID.str();
+    if (m_cfg.processVolumes && value.material) {
+      volj[m_cfg.matkey] = volumeMaterialToJson(*value.material);
+    }
+    // Write the layers
+    if (not value.layers.empty()) {
+      ACTS_VERBOSE("a2j: ---> Found " << value.layers.size() << " layer(s) ");
+      json layersj;
+      for (auto& [lkey, lvalue] : value.layers) {
+        ACTS_VERBOSE("a2j: ----> Convert layer " << lkey);
+        json layj;
+        std::ostringstream slayerID;
+        slayerID << lvalue.layerID;
+        layj[m_cfg.geometryidkey] = slayerID.str();
+        // First check for approaches
+        if (not lvalue.approaches.empty() and m_cfg.processApproaches) {
+          ACTS_VERBOSE("a2j: -----> Found " << lvalue.approaches.size()
+                                            << " approach surface(s)");
+          json approachesj;
+          for (auto& [akey, avalue] : lvalue.approaches) {
+            ACTS_VERBOSE("a2j: ------> Convert approach surface " << akey);
+            approachesj[std::to_string(akey)] = surfaceMaterialToJson(*avalue);
+            if (lvalue.approacheSurfaces.find(akey) !=
+                lvalue.approacheSurfaces.end())
+              addSurfaceToJson(approachesj[std::to_string(akey)],
+                               lvalue.approacheSurfaces.at(akey));
+          }
+          // Add to the layer json
+          layj[m_cfg.appkey] = approachesj;
+        }
+        // Then check for sensitive
+        if (not lvalue.sensitives.empty() and m_cfg.processSensitives) {
+          ACTS_VERBOSE("a2j: -----> Found " << lvalue.sensitives.size()
+                                            << " sensitive surface(s)");
+          json sensitivesj;
+          for (auto& [skey, svalue] : lvalue.sensitives) {
+            ACTS_VERBOSE("a2j: ------> Convert sensitive surface " << skey);
+            sensitivesj[std::to_string(skey)] = surfaceMaterialToJson(*svalue);
+            if (lvalue.sensitiveSurfaces.find(skey) !=
+                lvalue.sensitiveSurfaces.end())
+              addSurfaceToJson(sensitivesj[std::to_string(skey)],
+                               lvalue.sensitiveSurfaces.at(skey));
+          }
+          // Add to the layer json
+          layj[m_cfg.senkey] = sensitivesj;
+        }
+        // Finally check for representing
+        if (lvalue.representing != nullptr and m_cfg.processRepresenting) {
+          ACTS_VERBOSE("a2j: ------> Convert representing surface ");
+          layj[m_cfg.repkey] = surfaceMaterialToJson(*lvalue.representing);
+          if (lvalue.representingSurface != nullptr)
+            addSurfaceToJson(layj[m_cfg.repkey], lvalue.representingSurface);
+        }
+        layersj[std::to_string(lkey)] = layj;
+      }
+      volj[m_cfg.laykey] = layersj;
+    }
+    // Write the boundary surfaces
+    if (not value.boundaries.empty()) {
+      ACTS_VERBOSE("a2j: ---> Found " << value.boundaries.size()
+                                      << " boundary/ies ");
+      json boundariesj;
+      for (auto& [bkey, bvalue] : value.boundaries) {
+        ACTS_VERBOSE("a2j: ----> Convert boundary " << bkey);
+        boundariesj[std::to_string(bkey)] = surfaceMaterialToJson(*bvalue);
+        if (value.boundarySurfaces.find(bkey) != value.boundarySurfaces.end())
+          addSurfaceToJson(boundariesj[std::to_string(bkey)],
+                           value.boundarySurfaces.at(bkey));
+      }
+      volj[m_cfg.boukey] = boundariesj;
+    }
+
+    volumesj[std::to_string(key)] = volj;
+  }
+  // Assign the volume json to the detector json
+  detectorj[m_cfg.volkey] = volumesj;
+
+  return detectorj;
+}
+
+/// Create the Surface Material
+const Acts::ISurfaceMaterial*
+Acts::FaserActsJsonGeometryConverter::jsonToSurfaceMaterial(const json& material) {
+  Acts::ISurfaceMaterial* sMaterial = nullptr;
+  // The bin utility for deescribing the data
+  Acts::BinUtility bUtility;
+  for (auto& [key, value] : material.items()) {
+    if (key == m_cfg.transfokeys and not value.empty()) {
+      bUtility = Acts::BinUtility(jsonToTransform(value));
+      break;
+    }
+  }
+  // Convert the material
+  Acts::MaterialSlabMatrix mpMatrix;
+  // Structured binding
+  for (auto& [key, value] : material.items()) {
+    // Check json keys
+    if (key == m_cfg.bin0key and not value.empty()) {
+      bUtility += jsonToBinUtility(value);
+    } else if (key == m_cfg.bin1key and not value.empty()) {
+      bUtility += jsonToBinUtility(value);
+    }
+    if (key == m_cfg.datakey and not value.empty()) {
+      mpMatrix = jsonToMaterialMatrix(value);
+    }
+  }
+
+  // We have protoMaterial
+  if (mpMatrix.empty()) {
+    sMaterial = new Acts::ProtoSurfaceMaterial(bUtility);
+  } else if (bUtility.bins() == 1) {
+    sMaterial = new Acts::HomogeneousSurfaceMaterial(mpMatrix[0][0]);
+  } else {
+    sMaterial = new Acts::BinnedSurfaceMaterial(bUtility, mpMatrix);
+  }
+  // return what you have
+  return sMaterial;
+}
+
+/// Create the Volume Material
+const Acts::IVolumeMaterial* Acts::FaserActsJsonGeometryConverter::jsonToVolumeMaterial(
+    const json& material) {
+  Acts::IVolumeMaterial* vMaterial = nullptr;
+  // The bin utility for deescribing the data
+  Acts::BinUtility bUtility;
+  for (auto& [key, value] : material.items()) {
+    if (key == m_cfg.transfokeys and not value.empty()) {
+      bUtility = Acts::BinUtility(jsonToTransform(value));
+      break;
+    }
+  }
+  // Convert the material
+  std::vector<Material> mmat;
+  // Structured binding
+  for (auto& [key, value] : material.items()) {
+    // Check json keys
+    if (key == m_cfg.bin0key and not value.empty()) {
+      bUtility += jsonToBinUtility(value);
+    } else if (key == m_cfg.bin1key and not value.empty()) {
+      bUtility += jsonToBinUtility(value);
+    } else if (key == m_cfg.bin2key and not value.empty()) {
+      bUtility += jsonToBinUtility(value);
+    }
+    if (key == m_cfg.datakey and not value.empty()) {
+      for (const auto& bin : value) {
+        mmat.push_back(decodeMaterial(bin));
+      }
+    }
+  }
+
+  // We have protoMaterial
+  if (mmat.empty()) {
+    vMaterial = new Acts::ProtoVolumeMaterial(bUtility);
+  } else if (mmat.size() == 1) {
+    vMaterial = new Acts::HomogeneousVolumeMaterial(mmat[0]);
+  } else {
+    if (bUtility.dimensions() == 2) {
+      std::function<Acts::Vector2D(Acts::Vector3D)> transfoGlobalToLocal;
+      Acts::Grid2D grid = createGrid2D(bUtility, transfoGlobalToLocal);
+
+      Acts::Grid2D::point_t min = grid.minPosition();
+      Acts::Grid2D::point_t max = grid.maxPosition();
+      Acts::Grid2D::index_t nBins = grid.numLocalBins();
+
+      Acts::EAxis axis1(min[0], max[0], nBins[0]);
+      Acts::EAxis axis2(min[1], max[1], nBins[1]);
+
+      // Build the grid and fill it with data
+      MaterialGrid2D mGrid(std::make_tuple(axis1, axis2));
+
+      for (size_t bin = 0; bin < mmat.size(); bin++) {
+        mGrid.at(bin) = mmat[bin].parameters();
+      }
+      MaterialMapper<MaterialGrid2D> matMap(transfoGlobalToLocal, mGrid);
+      vMaterial =
+          new Acts::InterpolatedMaterialMap<MaterialMapper<MaterialGrid2D>>(
+              std::move(matMap), bUtility);
+    } else if (bUtility.dimensions() == 3) {
+      std::function<Acts::Vector3D(Acts::Vector3D)> transfoGlobalToLocal;
+      Acts::Grid3D grid = createGrid3D(bUtility, transfoGlobalToLocal);
+
+      Acts::Grid3D::point_t min = grid.minPosition();
+      Acts::Grid3D::point_t max = grid.maxPosition();
+      Acts::Grid3D::index_t nBins = grid.numLocalBins();
+
+      Acts::EAxis axis1(min[0], max[0], nBins[0]);
+      Acts::EAxis axis2(min[1], max[1], nBins[1]);
+      Acts::EAxis axis3(min[2], max[2], nBins[2]);
+
+      // Build the grid and fill it with data
+      MaterialGrid3D mGrid(std::make_tuple(axis1, axis2, axis3));
+
+      for (size_t bin = 0; bin < mmat.size(); bin++) {
+        mGrid.at(bin) = mmat[bin].parameters();
+      }
+      MaterialMapper<MaterialGrid3D> matMap(transfoGlobalToLocal, mGrid);
+      vMaterial =
+          new Acts::InterpolatedMaterialMap<MaterialMapper<MaterialGrid3D>>(
+              std::move(matMap), bUtility);
+    }
+  }
+  // return what you have
+  return vMaterial;
+}
+
+json Acts::FaserActsJsonGeometryConverter::trackingGeometryToJson(
+    const Acts::TrackingGeometry& tGeometry) {
+  DetectorRep detRep;
+  convertToRep(detRep, *tGeometry.highestTrackingVolume());
+  return detectorRepToJson(detRep);
+}
+
+void Acts::FaserActsJsonGeometryConverter::convertToRep(
+    DetectorRep& detRep, const Acts::TrackingVolume& tVolume) {
+  // The writer reader volume representation
+  VolumeRep volRep;
+  volRep.volumeName = tVolume.volumeName();
+  // there are confined volumes
+  if (tVolume.confinedVolumes() != nullptr) {
+    // get through the volumes
+    auto& volumes = tVolume.confinedVolumes()->arrayObjects();
+    // loop over the volumes
+    for (auto& vol : volumes) {
+      // recursive call
+      convertToRep(detRep, *vol);
+    }
+  }
+  // there are dense volumes
+  if (m_cfg.processDenseVolumes && !tVolume.denseVolumes().empty()) {
+    // loop over the volumes
+    for (auto& vol : tVolume.denseVolumes()) {
+      // recursive call
+      convertToRep(detRep, *vol);
+    }
+  }
+  // Get the volume Id
+  Acts::GeometryIdentifier volumeID = tVolume.geometryId();
+  geo_id_value vid = volumeID.volume();
+
+  // Write the material if there's one
+  if (tVolume.volumeMaterial() != nullptr) {
+    volRep.material = tVolume.volumeMaterial();
+  } else if (m_cfg.processnonmaterial == true) {
+    Acts::BinUtility bUtility = DefaultBin(tVolume);
+    Acts::IVolumeMaterial* bMaterial = new Acts::ProtoVolumeMaterial(bUtility);
+    volRep.material = bMaterial;
+  }
+  // there are confied layers
+  if (tVolume.confinedLayers() != nullptr) {
+    // get the layers
+    auto& layers = tVolume.confinedLayers()->arrayObjects();
+    // loop of the volumes
+    for (auto& lay : layers) {
+      auto layRep = convertToRep(*lay);
+      if (layRep) {
+        // it's a valid representation so let's go with it
+        Acts::GeometryIdentifier layerID = lay->geometryId();
+        geo_id_value lid = layerID.layer();
+        volRep.layers.insert({lid, std::move(layRep)});
+      }
+    }
+  }
+  // Let's finally check the boundaries
+  for (auto& bsurf : tVolume.boundarySurfaces()) {
+    // the surface representation
+    auto& bssfRep = bsurf->surfaceRepresentation();
+    if (bssfRep.surfaceMaterial() != nullptr) {
+      Acts::GeometryIdentifier boundaryID = bssfRep.geometryId();
+      geo_id_value bid = boundaryID.boundary();
+      // Ignore if the volumeID is not correct (i.e. shared boundary)
+      // if (boundaryID.value(Acts::GeometryIdentifier::volume_mask) == vid){
+      volRep.boundaries[bid] = bssfRep.surfaceMaterial();
+      volRep.boundarySurfaces[bid] = &bssfRep;
+      // }
+    } else if (m_cfg.processnonmaterial == true) {
+      // if no material suface exist add a default one for the mapping
+      // configuration
+      Acts::GeometryIdentifier boundaryID = bssfRep.geometryId();
+      geo_id_value bid = boundaryID.boundary();
+      Acts::BinUtility bUtility = DefaultBin(bssfRep);
+      Acts::ISurfaceMaterial* bMaterial =
+          new Acts::ProtoSurfaceMaterial(bUtility);
+      volRep.boundaries[bid] = bMaterial;
+      volRep.boundarySurfaces[bid] = &bssfRep;
+    }
+  }
+  // Write if it's good
+  if (volRep) {
+    volRep.volumeName = tVolume.volumeName();
+    volRep.volumeID = volumeID;
+    detRep.volumes.insert({vid, std::move(volRep)});
+  }
+  return;
+}
+
+Acts::FaserActsJsonGeometryConverter::LayerRep Acts::FaserActsJsonGeometryConverter::convertToRep(
+    const Acts::Layer& tLayer) {
+  LayerRep layRep;
+  // fill layer ID information
+  layRep.layerID = tLayer.geometryId();
+  if (m_cfg.processSensitives and tLayer.surfaceArray() != nullptr) {
+    for (auto& ssf : tLayer.surfaceArray()->surfaces()) {
+      if (ssf != nullptr && ssf->surfaceMaterial() != nullptr) {
+        Acts::GeometryIdentifier sensitiveID = ssf->geometryId();
+        geo_id_value sid = sensitiveID.sensitive();
+        layRep.sensitives.insert({sid, ssf->surfaceMaterial()});
+        layRep.sensitiveSurfaces.insert({sid, ssf});
+      } else if (m_cfg.processnonmaterial == true) {
+        // if no material suface exist add a default one for the mapping
+        // configuration
+        Acts::GeometryIdentifier sensitiveID = ssf->geometryId();
+        geo_id_value sid = sensitiveID.sensitive();
+        Acts::BinUtility sUtility = DefaultBin(*ssf);
+        Acts::ISurfaceMaterial* sMaterial =
+            new Acts::ProtoSurfaceMaterial(sUtility);
+        layRep.sensitives.insert({sid, sMaterial});
+        layRep.sensitiveSurfaces.insert({sid, ssf});
+      }
+    }
+  }
+  // the representing
+  if (!(tLayer.surfaceRepresentation().geometryId() == GeometryIdentifier())) {
+    if (tLayer.surfaceRepresentation().surfaceMaterial() != nullptr) {
+      layRep.representing = tLayer.surfaceRepresentation().surfaceMaterial();
+      layRep.representingSurface = &tLayer.surfaceRepresentation();
+    } else if (m_cfg.processnonmaterial == true) {
+      // if no material suface exist add a default one for the mapping
+      // configuration
+      Acts::BinUtility rUtility = DefaultBin(tLayer.surfaceRepresentation());
+      Acts::ISurfaceMaterial* rMaterial =
+          new Acts::ProtoSurfaceMaterial(rUtility);
+      layRep.representing = rMaterial;
+      layRep.representingSurface = &tLayer.surfaceRepresentation();
+    }
+  }
+  // the approach
+  if (tLayer.approachDescriptor() != nullptr) {
+    for (auto& asf : tLayer.approachDescriptor()->containedSurfaces()) {
+      // get the surface and check for material
+      if (asf->surfaceMaterial() != nullptr) {
+        Acts::GeometryIdentifier approachID = asf->geometryId();
+        geo_id_value aid = approachID.approach();
+        layRep.approaches.insert({aid, asf->surfaceMaterial()});
+        layRep.approacheSurfaces.insert({aid, asf});
+      } else if (m_cfg.processnonmaterial == true) {
+        // if no material suface exist add a default one for the mapping
+        // configuration
+        Acts::GeometryIdentifier approachID = asf->geometryId();
+        geo_id_value aid = approachID.approach();
+        Acts::BinUtility aUtility = DefaultBin(*asf);
+        Acts::ISurfaceMaterial* aMaterial =
+            new Acts::ProtoSurfaceMaterial(aUtility);
+        layRep.approaches.insert({aid, aMaterial});
+        layRep.approacheSurfaces.insert({aid, asf});
+      }
+    }
+  }
+  // return the layer representation
+  return layRep;
+}
+
+json Acts::FaserActsJsonGeometryConverter::surfaceMaterialToJson(
+    const Acts::ISurfaceMaterial& sMaterial) {
+  json smj;
+  // A bin utility needs to be written
+  const Acts::BinUtility* bUtility = nullptr;
+  // Check if we have a proto material
+  auto psMaterial = dynamic_cast<const Acts::ProtoSurfaceMaterial*>(&sMaterial);
+  if (psMaterial != nullptr) {
+    // Type is proto material
+    smj[m_cfg.typekey] = "proto";
+    // by default the protoMaterial is not used for mapping
+    smj[m_cfg.mapkey] = false;
+    bUtility = &(psMaterial->binUtility());
+  } else {
+    // Now check if we have a homogeneous material
+    auto hsMaterial =
+        dynamic_cast<const Acts::HomogeneousSurfaceMaterial*>(&sMaterial);
+    if (hsMaterial != nullptr) {
+      // type is homogeneous
+      smj[m_cfg.typekey] = "homogeneous";
+      smj[m_cfg.mapkey] = true;
+      if (m_cfg.writeData) {
+        smj[m_cfg.datakey] = json::array({
+            json::array({
+                encodeMaterialSlab(hsMaterial->materialSlab(0, 0)),
+            }),
+        });
+      }
+    } else {
+      // Only option remaining: BinnedSurface material
+      auto bsMaterial =
+          dynamic_cast<const Acts::BinnedSurfaceMaterial*>(&sMaterial);
+      if (bsMaterial != nullptr) {
+        // type is binned
+        smj[m_cfg.typekey] = "binned";
+        smj[m_cfg.mapkey] = true;
+        bUtility = &(bsMaterial->binUtility());
+        // convert the data
+        // get the material matrix
+        if (m_cfg.writeData) {
+          json mmat = json::array();
+          for (const auto& mpVector : bsMaterial->fullMaterial()) {
+            json mvec = json::array();
+            for (const auto& mp : mpVector) {
+              mvec.push_back(encodeMaterialSlab(mp));
+            }
+            mmat.push_back(std::move(mvec));
+          }
+          smj[m_cfg.datakey] = std::move(mmat);
+        }
+      }
+    }
+  }
+  // add the bin utility
+  if (bUtility != nullptr && !bUtility->binningData().empty()) {
+    std::vector<std::string> binkeys = {m_cfg.bin0key, m_cfg.bin1key};
+    // loop over dimensions and write
+    auto& binningData = bUtility->binningData();
+    // loop over the dimensions
+    for (size_t ibin = 0; ibin < binningData.size(); ++ibin) {
+      json binj;
+      auto cbData = binningData[ibin];
+      binj.push_back(Acts::binningValueNames[cbData.binvalue]);
+      if (cbData.option == Acts::closed) {
+        binj.push_back("closed");
+      } else {
+        binj.push_back("open");
+      }
+      binj.push_back(cbData.bins());
+      // If protoMaterial has a non uniform binning (non default) then it is
+      // used by default in the mapping
+      if (smj[m_cfg.typekey] == "proto" && cbData.bins() > 1)
+        smj[m_cfg.mapkey] = true;
+      // If it's not a proto map, write min / max
+      if (smj[m_cfg.typekey] != "proto") {
+        std::pair<double, double> minMax = {cbData.min, cbData.max};
+        binj.push_back(minMax);
+      }
+      smj[binkeys[ibin]] = binj;
+    }
+    std::vector<double> transfo;
+    Acts::Transform3D transfo_matrix = bUtility->transform();
+    if (not transfo_matrix.isApprox(Acts::Transform3D::Identity())) {
+      for (int i = 0; i < 4; i++) {
+        for (int j = 0; j < 4; j++) {
+          transfo.push_back(transfo_matrix(j, i));
+        }
+      }
+      smj[m_cfg.transfokeys] = transfo;
+    }
+  }
+  return smj;
+}
+
+json Acts::FaserActsJsonGeometryConverter::volumeMaterialToJson(
+    const Acts::IVolumeMaterial& vMaterial) {
+  json smj;
+  // A bin utility needs to be written
+  const Acts::BinUtility* bUtility = nullptr;
+  // Check if we have a proto material
+  auto pvMaterial = dynamic_cast<const Acts::ProtoVolumeMaterial*>(&vMaterial);
+  if (pvMaterial != nullptr) {
+    // Type is proto material
+    smj[m_cfg.typekey] = "proto";
+    // by default the protoMaterial is not used for mapping
+    smj[m_cfg.mapkey] = false;
+    bUtility = &(pvMaterial->binUtility());
+  } else {
+    // Now check if we have a homogeneous material
+    auto hvMaterial =
+        dynamic_cast<const Acts::HomogeneousVolumeMaterial*>(&vMaterial);
+    if (hvMaterial != nullptr) {
+      // type is homogeneous
+      smj[m_cfg.typekey] = "homogeneous";
+      smj[m_cfg.mapkey] = true;
+      if (m_cfg.writeData) {
+        // array of encoded materials w/ one entry
+        smj[m_cfg.datakey] = json::array({
+            encodeMaterial(hvMaterial->material({0, 0, 0})),
+        });
+      }
+    } else {
+      // Only option remaining: material map
+      auto bvMaterial2D = dynamic_cast<
+          const Acts::InterpolatedMaterialMap<MaterialMapper<MaterialGrid2D>>*>(
+          &vMaterial);
+      // Now check if we have a 2D map
+      if (bvMaterial2D != nullptr) {
+        // type is binned
+        smj[m_cfg.typekey] = "interpolated2D";
+        smj[m_cfg.mapkey] = true;
+        bUtility = &(bvMaterial2D->binUtility());
+        // convert the data
+        if (m_cfg.writeData) {
+          json mmat = json::array();
+          MaterialGrid2D grid = bvMaterial2D->getMapper().getGrid();
+          for (size_t bin = 0; bin < grid.size(); bin++) {
+            mmat.push_back(encodeMaterial(grid.at(bin)));
+          }
+          smj[m_cfg.datakey] = std::move(mmat);
+        }
+      } else {
+        // Only option remaining: material map
+        auto bvMaterial3D = dynamic_cast<const Acts::InterpolatedMaterialMap<
+            MaterialMapper<MaterialGrid3D>>*>(&vMaterial);
+        // Now check if we have a 3D map
+        if (bvMaterial3D != nullptr) {
+          // type is binned
+          smj[m_cfg.typekey] = "interpolated3D";
+          smj[m_cfg.mapkey] = true;
+          bUtility = &(bvMaterial3D->binUtility());
+          // convert the data
+          if (m_cfg.writeData) {
+            json mmat = json::array();
+            MaterialGrid3D grid = bvMaterial3D->getMapper().getGrid();
+            for (size_t bin = 0; bin < grid.size(); bin++) {
+              mmat.push_back(encodeMaterial(grid.at(bin)));
+            }
+            smj[m_cfg.datakey] = std::move(mmat);
+          }
+        }
+      }
+    }
+  }
+  // add the bin utility
+  if (bUtility != nullptr && !bUtility->binningData().empty()) {
+    std::vector<std::string> binkeys = {m_cfg.bin0key, m_cfg.bin1key,
+                                        m_cfg.bin2key};
+    // loop over dimensions and write
+    auto& binningData = bUtility->binningData();
+    // loop over the dimensions
+    for (size_t ibin = 0; ibin < binningData.size(); ++ibin) {
+      json binj;
+      auto cbData = binningData[ibin];
+      binj.push_back(Acts::binningValueNames[cbData.binvalue]);
+      if (cbData.option == Acts::closed) {
+        binj.push_back("closed");
+      } else {
+        binj.push_back("open");
+      }
+      binj.push_back(cbData.bins());
+      // If protoMaterial has a non uniform binning (non default) then it is
+      // used by default in the mapping
+      if (smj[m_cfg.typekey] == "proto" && cbData.bins() > 1)
+        smj[m_cfg.mapkey] = true;
+      // If it's not a proto map, write min / max
+      if (smj[m_cfg.typekey] != "proto") {
+        std::pair<double, double> minMax = {cbData.min, cbData.max};
+        binj.push_back(minMax);
+      }
+      smj[binkeys[ibin]] = binj;
+    }
+    std::vector<double> transfo;
+    Acts::Transform3D transfo_matrix = bUtility->transform();
+    for (int i = 0; i < 4; i++) {
+      for (int j = 0; j < 4; j++) {
+        transfo.push_back(transfo_matrix(j, i));
+      }
+    }
+    smj[m_cfg.transfokeys] = transfo;
+  }
+  return smj;
+}
+
+void Acts::FaserActsJsonGeometryConverter::addSurfaceToJson(json& sjson,
+                                                   const Surface* surface) {
+  // Get the ID of the surface (redundant but help readability)
+  std::ostringstream SurfaceID;
+  SurfaceID << surface->geometryId();
+  sjson[m_cfg.surfacegeometryidkey] = SurfaceID.str();
+
+  // Cast the surface bound to both disk and cylinder
+  const Acts::SurfaceBounds& surfaceBounds = surface->bounds();
+  auto sTransform = surface->transform(GeometryContext());
+
+  const Acts::RadialBounds* radialBounds =
+      dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds);
+  const Acts::CylinderBounds* cylinderBounds =
+      dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds);
+  const Acts::AnnulusBounds* annulusBounds =
+      dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds);
+
+  if (radialBounds != nullptr) {
+    sjson[m_cfg.surfacetypekey] = "Disk";
+    sjson[m_cfg.surfacepositionkey] = sTransform.translation().z();
+    sjson[m_cfg.surfacerangekey] = {radialBounds->rMin(), radialBounds->rMax()};
+  }
+  if (cylinderBounds != nullptr) {
+    sjson[m_cfg.surfacetypekey] = "Cylinder";
+    sjson[m_cfg.surfacepositionkey] = cylinderBounds->get(CylinderBounds::eR);
+    sjson[m_cfg.surfacerangekey] = {
+        -1 * cylinderBounds->get(CylinderBounds::eHalfLengthZ),
+        cylinderBounds->get(CylinderBounds::eHalfLengthZ)};
+  }
+  if (annulusBounds != nullptr) {
+    sjson[m_cfg.surfacetypekey] = "Annulus";
+    sjson[m_cfg.surfacepositionkey] = sTransform.translation().z();
+    sjson[m_cfg.surfacerangekey] = {
+        {annulusBounds->rMin(), annulusBounds->rMax()},
+        {annulusBounds->phiMin(), annulusBounds->phiMax()}};
+  }
+}
+
+/// Create the Material Matrix
+Acts::MaterialSlabMatrix Acts::FaserActsJsonGeometryConverter::jsonToMaterialMatrix(
+    const json& data) {
+  Acts::MaterialSlabMatrix mpMatrix;
+  // the input data must be array[array[object]]
+  for (auto& outer : data) {
+    Acts::MaterialSlabVector mpVector;
+    for (auto& inner : outer) {
+      mpVector.emplace_back(decodeMaterialSlab(inner));
+    }
+    mpMatrix.push_back(std::move(mpVector));
+  }
+  return mpMatrix;
+}
+
+/// Create the BinUtility for this
+Acts::BinUtility Acts::FaserActsJsonGeometryConverter::jsonToBinUtility(
+    const json& bin) {
+  if (bin.size() >= 3) {
+    // finding the iterator position to determine the binning value
+    auto bit = std::find(Acts::binningValueNames.begin(),
+                         Acts::binningValueNames.end(), bin[0]);
+    size_t indx = std::distance(Acts::binningValueNames.begin(), bit);
+    Acts::BinningValue bval = Acts::BinningValue(indx);
+    Acts::BinningOption bopt = bin[1] == "open" ? Acts::open : Acts::closed;
+    unsigned int bins = bin[2];
+    float min = 0;
+    float max = 0;
+    if (bin.size() >= 4 && bin[3].size() == 2) {
+      min = bin[3][0];
+      max = bin[3][1];
+    }
+    return Acts::BinUtility(bins, min, max, bopt, bval);
+  }
+  return Acts::BinUtility();
+}
+
+/// Create the local to global transform
+Acts::Transform3D Acts::FaserActsJsonGeometryConverter::jsonToTransform(
+    const json& transfo) {
+  Transform3D transform;
+  int i = 0;
+  int j = 0;
+  for (auto& element : transfo) {
+    transform(j, i) = element;
+    j++;
+    if (j == 4) {
+      i++;
+      j = 0;
+    }
+  }
+  return transform;
+}
+
+Acts::BinUtility Acts::FaserActsJsonGeometryConverter::DefaultBin(
+    const Acts::Surface& surface) {
+  Acts::BinUtility bUtility;
+
+  const Acts::SurfaceBounds& surfaceBounds = surface.bounds();
+  const Acts::RadialBounds* radialBounds =
+      dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds);
+  const Acts::CylinderBounds* cylinderBounds =
+      dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds);
+  const Acts::AnnulusBounds* annulusBounds =
+      dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds);
+  const Acts::RectangleBounds* rectangleBounds =
+      dynamic_cast<const Acts::RectangleBounds*>(&surfaceBounds);
+
+  if (radialBounds != nullptr) {
+    bUtility += BinUtility(
+        1,
+        radialBounds->get(RadialBounds::eAveragePhi) -
+            radialBounds->get(RadialBounds::eHalfPhiSector),
+        radialBounds->get(RadialBounds::eAveragePhi) +
+            radialBounds->get(RadialBounds::eHalfPhiSector),
+        (radialBounds->get(RadialBounds::eHalfPhiSector) - M_PI) < s_epsilon
+            ? Acts::closed
+            : Acts::open,
+        Acts::binPhi);
+    bUtility += BinUtility(1, radialBounds->rMin(), radialBounds->rMax(),
+                           Acts::open, Acts::binR);
+    return bUtility;
+  }
+  if (cylinderBounds != nullptr) {
+    bUtility += BinUtility(
+        1,
+        cylinderBounds->get(CylinderBounds::eAveragePhi) -
+            cylinderBounds->get(CylinderBounds::eHalfPhiSector),
+        cylinderBounds->get(CylinderBounds::eAveragePhi) +
+            cylinderBounds->get(CylinderBounds::eHalfPhiSector),
+        (cylinderBounds->get(CylinderBounds::eHalfPhiSector) - M_PI) < s_epsilon
+            ? Acts::closed
+            : Acts::open,
+        Acts::binPhi);
+    bUtility +=
+        BinUtility(1, -1 * cylinderBounds->get(CylinderBounds::eHalfLengthZ),
+                   cylinderBounds->get(CylinderBounds::eHalfLengthZ),
+                   Acts::open, Acts::binZ);
+    return bUtility;
+  }
+  if (annulusBounds != nullptr) {
+    bUtility += BinUtility(1, annulusBounds->get(AnnulusBounds::eMinPhiRel),
+                           annulusBounds->get(AnnulusBounds::eMaxPhiRel),
+                           Acts::open, Acts::binPhi);
+    bUtility += BinUtility(1, annulusBounds->rMin(), annulusBounds->rMax(),
+                           Acts::open, Acts::binR);
+    return bUtility;
+  }
+  if (rectangleBounds != nullptr) {
+    bUtility += BinUtility(1, rectangleBounds->get(RectangleBounds::eMinX),
+                           rectangleBounds->get(RectangleBounds::eMaxX),
+                           Acts::open, Acts::binX);
+    bUtility += BinUtility(1, rectangleBounds->get(RectangleBounds::eMinY),
+                           rectangleBounds->get(RectangleBounds::eMaxY),
+                           Acts::open, Acts::binY);
+    return bUtility;
+  }
+  ACTS_INFO(
+      "No corresponding bound found for the surface : " << surface.name());
+  return bUtility;
+}
+
+Acts::BinUtility Acts::FaserActsJsonGeometryConverter::DefaultBin(
+    const Acts::TrackingVolume& volume) {
+  Acts::BinUtility bUtility;
+
+  auto cyBounds =
+      dynamic_cast<const CylinderVolumeBounds*>(&(volume.volumeBounds()));
+  auto cutcylBounds =
+      dynamic_cast<const CutoutCylinderVolumeBounds*>(&(volume.volumeBounds()));
+  auto cuBounds =
+      dynamic_cast<const CuboidVolumeBounds*>(&(volume.volumeBounds()));
+
+  if (cyBounds != nullptr) {
+    bUtility += BinUtility(1, cyBounds->get(CylinderVolumeBounds::eMinR),
+                           cyBounds->get(CylinderVolumeBounds::eMaxR),
+                           Acts::open, Acts::binR);
+    bUtility += BinUtility(
+        1, -cyBounds->get(CylinderVolumeBounds::eHalfPhiSector),
+        cyBounds->get(CylinderVolumeBounds::eHalfPhiSector),
+        (cyBounds->get(CylinderVolumeBounds::eHalfPhiSector) - M_PI) < s_epsilon
+            ? Acts::closed
+            : Acts::open,
+        Acts::binPhi);
+    bUtility +=
+        BinUtility(1, -cyBounds->get(CylinderVolumeBounds::eHalfLengthZ),
+                   cyBounds->get(CylinderVolumeBounds::eHalfLengthZ),
+                   Acts::open, Acts::binZ);
+    return bUtility;
+  }
+  if (cutcylBounds != nullptr) {
+    bUtility +=
+        BinUtility(1, cutcylBounds->get(CutoutCylinderVolumeBounds::eMinR),
+                   cutcylBounds->get(CutoutCylinderVolumeBounds::eMaxR),
+                   Acts::open, Acts::binR);
+    bUtility += BinUtility(1, -M_PI, M_PI, Acts::closed, Acts::binPhi);
+    bUtility += BinUtility(
+        1, -cutcylBounds->get(CutoutCylinderVolumeBounds::eHalfLengthZ),
+        cutcylBounds->get(CutoutCylinderVolumeBounds::eHalfLengthZ), Acts::open,
+        Acts::binZ);
+    return bUtility;
+  } else if (cuBounds != nullptr) {
+    bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthX),
+                           cuBounds->get(CuboidVolumeBounds::eHalfLengthX),
+                           Acts::open, Acts::binX);
+    bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthY),
+                           cuBounds->get(CuboidVolumeBounds::eHalfLengthY),
+                           Acts::open, Acts::binY);
+    bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthZ),
+                           cuBounds->get(CuboidVolumeBounds::eHalfLengthZ),
+                           Acts::open, Acts::binZ);
+    return bUtility;
+  }
+  ACTS_INFO(
+      "No corresponding bound found for the volume : " << volume.volumeName());
+  return bUtility;
+}
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fe033f8eba019c77761c8edb6f8e89501f31bd89
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx
@@ -0,0 +1,62 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserActsGeometry/FaserActsMaterialJsonWriterTool.h"
+
+#include "ActsInterop/Logger.h"
+
+#include <fstream>
+#include <ios>
+#include <iostream>
+#include <stdexcept>
+
+// FaserActsMaterialJsonWriterTool::FaserActsMaterialJsonWriterTool(const std::string& type, const std::string& name, const IInterface* parent) :
+//   base_class(type, name, parent)
+// {
+// }
+FaserActsMaterialJsonWriterTool::FaserActsMaterialJsonWriterTool(const std::string &type, const std::string &name,
+                                const IInterface *parent)
+  : base_class(type, name, parent)
+{
+}
+
+StatusCode
+FaserActsMaterialJsonWriterTool::initialize()
+{
+  ATH_MSG_INFO("Starting Material writer");
+
+  m_cfg.name = "FaserActsJsonGeometryConverter";
+  m_cfg.logger = makeActsAthenaLogger(this, "FaserActsJsonGeometryConverter");
+  m_cfg.processSensitives = m_processSensitives;
+  m_cfg.processApproaches = m_processApproaches;
+  m_cfg.processRepresenting = m_processRepresenting;
+  m_cfg.processBoundaries = m_processBoundaries;
+  m_cfg.processVolumes = m_processVolumes;
+  m_cfg.processDenseVolumes = m_processDenseVolumes;
+  m_cfg.processnonmaterial = m_processnonmaterial;
+  
+  return StatusCode::SUCCESS;
+}
+
+void
+FaserActsMaterialJsonWriterTool::write(const Acts::FaserActsJsonGeometryConverter::DetectorMaterialMaps& detMaterial) const
+{
+  // Evoke the converter
+  Acts::FaserActsJsonGeometryConverter jmConverter(m_cfg);
+  auto jout = jmConverter.materialMapsToJson(detMaterial);
+  // And write the file
+  std::ofstream ofj(m_filePath);
+  ofj << std::setw(4) << jout << std::endl;
+}
+
+void
+FaserActsMaterialJsonWriterTool::write(const Acts::TrackingGeometry& tGeometry) const
+{
+  // Evoke the converter
+  Acts::FaserActsJsonGeometryConverter jmConverter(m_cfg);
+  auto jout = jmConverter.trackingGeometryToJson(tGeometry);
+  // And write the file
+  std::ofstream ofj(m_filePath);
+  ofj << std::setw(4) << jout << std::endl;
+}
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..70a2ccec59d4d37ef5b76dfd2b20274e5cbdea37
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserActsGeometry/FaserActsMaterialMapping.h"
+
+// ATHENA
+#include "Acts/Surfaces/PerigeeSurface.hpp"
+#include "Acts/Utilities/Logger.hpp"
+#include "ActsInterop/Logger.h"
+#include "GaudiKernel/EventContext.h"
+#include "GaudiKernel/ISvcLocator.h"
+
+// ACTS
+#include "Acts/Propagator/detail/SteppingLogger.hpp"
+#include "Acts/Utilities/Helpers.hpp"
+#include "Acts/Utilities/Units.hpp"
+
+// PACKAGE
+#include "FaserActsGeometry/FaserActsGeometryContext.h"
+#include "FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h"
+
+// STL
+#include <fstream>
+#include <string>
+
+//TEST
+#include "Acts/EventData/NeutralTrackParameters.hpp"
+#include "Acts/Propagator/ActionList.hpp"
+#include "Acts/Propagator/Navigator.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/StandardAborters.hpp"
+#include "Acts/Propagator/StraightLineStepper.hpp"
+
+FaserActsMaterialMapping::FaserActsMaterialMapping(const std::string &name,
+                                           ISvcLocator *pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator),
+      m_materialTrackWriterSvc("ActsMaterialTrackWriterSvc", name),
+      m_inputMaterialStepCollection("MaterialStepRecords"),
+      m_mappingState(m_gctx,m_mctx),
+      m_mappingStateVol(m_gctx,m_mctx)
+{}
+
+StatusCode FaserActsMaterialMapping::initialize() {
+  ATH_MSG_DEBUG(name() << "::" << __FUNCTION__);
+
+  if(!m_mapSurfaces && !m_mapVolumes){
+    ATH_MSG_ERROR("No element to map onto defined.");
+    return StatusCode::FAILURE;
+  }
+
+  ATH_CHECK(m_materialStepConverterTool.retrieve() );
+  ATH_CHECK(m_materialTrackWriterSvc.retrieve() );
+  if(m_mapSurfaces){
+    ATH_CHECK(m_surfaceMappingTool.retrieve() );
+    m_mappingState = m_surfaceMappingTool->mappingState();
+  }
+  if(m_mapVolumes){
+    ATH_CHECK(m_volumeMappingTool.retrieve() );
+    m_mappingStateVol = m_volumeMappingTool->mappingState();
+  }
+  ATH_CHECK(m_materialJsonWriterTool.retrieve() );
+  ATH_CHECK( m_inputMaterialStepCollection.initialize() );
+  return StatusCode::SUCCESS;
+}
+
+StatusCode FaserActsMaterialMapping::execute(const EventContext &ctx) const {
+  ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__);
+
+  Acts::RecordedMaterialTrack mTrack;
+  SG::ReadHandle<Trk::MaterialStepCollection> materialStepCollection(m_inputMaterialStepCollection, ctx);
+  mTrack = m_materialStepConverterTool->convertToMaterialTrack(*materialStepCollection);
+
+  if(m_mapSurfaces){
+    auto mappingState
+         = const_cast<Acts::SurfaceMaterialMapper::State *>(&m_mappingState);
+    m_surfaceMappingTool->mapper()->mapMaterialTrack(*mappingState, mTrack);
+  }
+  if(m_mapVolumes){
+    auto mappingStateVol
+         = const_cast<Acts::VolumeMaterialMapper::State *>(&m_mappingStateVol);
+    m_volumeMappingTool->mapper()->mapMaterialTrack(*mappingStateVol, mTrack);
+  }
+  m_materialTrackWriterSvc->write(mTrack);
+  ATH_MSG_VERBOSE(name() << " execute done");
+  return StatusCode::SUCCESS;
+}
+
+StatusCode FaserActsMaterialMapping::finalize() {
+
+  Acts::DetectorMaterialMaps detectorMaterial;
+
+  // Finalize all the maps using the cached state
+  if(m_mapSurfaces && m_mapVolumes){
+    m_surfaceMappingTool->mapper()->finalizeMaps(m_mappingState);
+    m_volumeMappingTool->mapper()->finalizeMaps(m_mappingStateVol);
+    // Loop over the state, and collect the maps for surfaces
+    for (auto& [key, value] : m_mappingState.surfaceMaterial) {
+      detectorMaterial.first.insert({key, std::move(value)});
+    }
+    // Loop over the state, and collect the maps for volumes
+    for (auto& [key, value] : m_mappingStateVol.volumeMaterial) {
+      detectorMaterial.second.insert({key, std::move(value)});
+    }
+  }
+  else{
+    if(m_mapSurfaces){
+      m_surfaceMappingTool->mapper()->finalizeMaps(m_mappingState);
+      // Loop over the state, and collect the maps for surfaces
+      for (auto& [key, value] : m_mappingState.surfaceMaterial) {
+        detectorMaterial.first.insert({key, std::move(value)});
+      }
+      // Loop over the state, and collect the maps for volumes
+      for (auto& [key, value] : m_mappingState.volumeMaterial) {
+        detectorMaterial.second.insert({key, std::move(value)});
+      }
+    }
+    if(m_mapVolumes){
+      m_volumeMappingTool->mapper()->finalizeMaps(m_mappingStateVol);
+      // Loop over the state, and collect the maps for surfaces
+      for (auto& [key, value] : m_mappingStateVol.surfaceMaterial) {
+        detectorMaterial.first.insert({key, std::move(value)});
+      }
+      // Loop over the state, and collect the maps for volumes
+      for (auto& [key, value] : m_mappingStateVol.volumeMaterial) {
+        detectorMaterial.second.insert({key, std::move(value)});
+      }
+    }
+  }
+  
+  m_materialJsonWriterTool->write(detectorMaterial);
+
+  return StatusCode::SUCCESS;
+
+}
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e2ff5c10694dab663d896a1440e4355606edcaf2
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserActsGeometry/FaserActsSurfaceMappingTool.h"
+
+// ATHENA
+#include "GaudiKernel/IInterface.h"
+// PACKAGE
+#include "ActsInterop/Logger.h"
+#include "FaserActsGeometry/FaserActsGeometryContext.h"
+#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+
+// ACTS
+#include "Acts/Geometry/GeometryContext.hpp"
+#include "Acts/Propagator/Navigator.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/StraightLineStepper.hpp"
+
+// STL
+#include <iostream>
+#include <memory>
+
+
+FaserActsSurfaceMappingTool::FaserActsSurfaceMappingTool(const std::string& type, const std::string& name,
+    const IInterface* parent)
+  : base_class(type, name, parent)
+{
+}
+
+StatusCode
+FaserActsSurfaceMappingTool::initialize()
+{
+  ATH_MSG_INFO("Initializing ACTS Surface Mapper");
+
+  ATH_CHECK( m_trackingGeometryTool.retrieve() );
+
+  m_trackingGeometry = m_trackingGeometryTool->trackingGeometry();
+
+  Acts::Navigator navigator(m_trackingGeometry);
+  // Make stepper and propagator
+  SlStepper stepper;
+  StraightLinePropagator propagator = StraightLinePropagator(std::move(stepper), std::move(navigator));
+
+  /// The material mapper
+  Acts::SurfaceMaterialMapper::Config smmConfig;
+  smmConfig.mapperDebugOutput = true;
+  m_mapper = std::make_shared<Acts::SurfaceMaterialMapper>(
+      smmConfig,
+      std::move(propagator),
+      makeActsAthenaLogger(this, "SurfaceMaterialMapper"));
+
+  m_geoContext = m_trackingGeometryTool->getNominalGeometryContext().any();
+
+  ATH_MSG_INFO("ACTS Surface Mapper successfully initialized");
+  return StatusCode::SUCCESS;
+}
+
+Acts::SurfaceMaterialMapper::State
+FaserActsSurfaceMappingTool::mappingState() const
+{
+  auto mappingState = m_mapper->createState(
+    m_geoContext, m_magFieldContext, *m_trackingGeometry);
+
+  return mappingState;
+}
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..234a7f2be7741ed7e41f56cc43338702418cff35
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserActsGeometry/FaserActsVolumeMappingTool.h"
+
+// ATHENA
+#include "GaudiKernel/IInterface.h"
+
+// PACKAGE
+#include "FaserActsGeometry/FaserActsGeometryContext.h"
+#include "ActsInterop/Logger.h"
+#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h"
+//#include "ActsGeometry/ActsGeometryContext.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+
+// ACTS
+#include "Acts/Propagator/Navigator.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/StraightLineStepper.hpp"
+#include "Acts/Geometry/GeometryContext.hpp"
+
+// STL
+#include <iostream>
+#include <memory>
+
+
+FaserActsVolumeMappingTool::FaserActsVolumeMappingTool(const std::string& type, const std::string& name,
+    const IInterface* parent)
+  : base_class(type, name, parent)
+{
+}
+
+StatusCode
+FaserActsVolumeMappingTool::initialize()
+{
+  ATH_MSG_INFO("Initializing ACTS Volume Mapper");
+
+  ATH_CHECK( m_trackingGeometryTool.retrieve() );
+
+  m_trackingGeometry = m_trackingGeometryTool->trackingGeometry();
+
+  Acts::Navigator navigator(m_trackingGeometry);
+  // Make stepper and propagator
+  SlStepper stepper;
+  StraightLinePropagator propagator = StraightLinePropagator(std::move(stepper), std::move(navigator));
+
+  /// The material mapper
+  Acts::VolumeMaterialMapper::Config smmConfig;
+  smmConfig.mappingStep = 10;
+  m_mapper = std::make_shared<Acts::VolumeMaterialMapper>(
+      smmConfig,
+      std::move(propagator),
+      makeActsAthenaLogger(this, "VolumeMaterialMapper"));
+
+  m_geoContext = m_trackingGeometryTool->getNominalGeometryContext().any();
+
+  ATH_MSG_INFO("ACTS Surface Mapper successfully initialized");
+  return StatusCode::SUCCESS;
+}
+
+Acts::VolumeMaterialMapper::State
+FaserActsVolumeMappingTool::mappingState() const
+{
+  auto mappingState = m_mapper->createState(
+    m_geoContext, m_magFieldContext, *m_trackingGeometry);
+
+  return mappingState;
+}
diff --git a/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx b/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx
index 9ad80a9d5d68164965de8c40d355bd9fc02e05ae..9be7649a9397fa25de520848ede7ecad3bcc4cc7 100755
--- a/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx
+++ b/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx
@@ -16,7 +16,10 @@
 //#include "FaserActsGeometry/FaserActsMaterialTrackWriterSvc.h"
 //#include "FaserActsGeometry/GeomShiftCondAlg.h"
 //#include "FaserActsGeometry/FaserActsWriteTrackingGeometryTransforms.h"
-
+#include "FaserActsGeometry/FaserActsVolumeMappingTool.h"
+#include "FaserActsGeometry/FaserActsMaterialJsonWriterTool.h"
+#include "FaserActsGeometry/FaserActsMaterialMapping.h"
+#include "FaserActsGeometry/FaserActsSurfaceMappingTool.h"
 
 DECLARE_COMPONENT( FaserActsTrackingGeometrySvc )
 DECLARE_COMPONENT( FaserActsTrackingGeometryTool )
@@ -32,3 +35,7 @@ DECLARE_COMPONENT( FaserActsAlignmentCondAlg )
 //DECLARE_COMPONENT( FaserActsMaterialTrackWriterSvc )
 //DECLARE_COMPONENT( FaserActsWriteTrackingGeometryTransforms )
 //DECLARE_COMPONENT( FaserGeomShiftCondAlg )
+DECLARE_COMPONENT( FaserActsVolumeMappingTool )
+DECLARE_COMPONENT( FaserActsMaterialJsonWriterTool )
+DECLARE_COMPONENT( FaserActsMaterialMapping )
+DECLARE_COMPONENT( FaserActsSurfaceMappingTool )
diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt b/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt
index 633d8584e7fb89fbfe48d84c3eb634eae4807b56..7529f472a8de702fb76046cb78624a9111e65a03 100644
--- a/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt
@@ -5,7 +5,7 @@ atlas_subdir( FaserActsGeometryInterfaces )
 # External dependencies:
 find_package( Eigen )
 find_package( Acts COMPONENTS Core )
-
+find_package( nlohmann_json )
 # Component(s) in the package:
 
 atlas_add_library( FaserActsGeometryInterfacesLib
@@ -13,7 +13,7 @@ atlas_add_library( FaserActsGeometryInterfacesLib
                    INTERFACE
                    PUBLIC_HEADERS FaserActsGeometryInterfaces
                    INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}
-                   LINK_LIBRARIES ${EIGEN_LIBRARIES}
+                   LINK_LIBRARIES ${EIGEN_LIBRARIES} nlohmann_json::nlohmann_json
                    AthenaKernel
                    ActsInteropLib
                    ActsCore)
diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fe13c593aaee7207a8da54909ee1e21eba09564
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ACTSGEOMETRY_IFASERACTSMATERIALJSONWRITERTOOL_H
+#define ACTSGEOMETRY_IFASERACTSMATERIALJSONWRITERTOOL_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/IAlgTool.h"
+
+#include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/Plugins/Json/JsonGeometryConverter.hpp"
+#include "FaserActsGeometry/FaserActsJsonGeometryConverter.h"
+
+namespace Acts {
+  class TrackingGeometry;
+}
+
+class IFaserActsMaterialJsonWriterTool : virtual public IAlgTool {
+public:
+
+  DeclareInterfaceID(IFaserActsMaterialJsonWriterTool, 1, 0);
+
+  virtual
+  void
+  write(const Acts::FaserActsJsonGeometryConverter::DetectorMaterialMaps& detMaterial) const = 0;
+
+  virtual
+  void
+  write(const Acts::TrackingGeometry& tGeometry) const = 0;
+
+};
+
+
+#endif
diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsSurfaceMappingTool.h b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsSurfaceMappingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..29563126d11605363601d857f9adcbf94512ab5c
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsSurfaceMappingTool.h
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERACTSGEOMETRYINTERFACES_IFASERACTSSURFACEMAPPINGTOOL_H
+#define FASERACTSGEOMETRYINTERFACES_IFASERACTSSURFACEMAPPINGTOOL_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/EventContext.h"
+
+#include "Acts/Material/SurfaceMaterialMapper.hpp"
+
+class IFaserActsTrackingGeometryTool;
+
+class IFaserActsSurfaceMappingTool : virtual public IAlgTool {
+  public:
+
+  DeclareInterfaceID(IFaserActsSurfaceMappingTool, 1, 0);
+
+
+  virtual
+  std::shared_ptr<Acts::SurfaceMaterialMapper>
+  mapper() const = 0;
+
+  virtual
+  Acts::SurfaceMaterialMapper::State
+  mappingState() const = 0;
+
+  virtual
+  const IFaserActsTrackingGeometryTool*
+  trackingGeometryTool() const = 0;
+
+};
+
+#endif
diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h
index e13ff4454b95a16de7b8932bd002260432d80069..823279417d1ef87d8ca00287a36214aabf7d623c 100644
--- a/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h
+++ b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h
@@ -2,8 +2,8 @@
   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 
-#ifndef FASERACTSGEOMETRYINTERFACES_IACTSTRACKINGGEOMETRYTOOL_H
-#define FASERACTSGEOMETRYINTERFACES_IACTSTRACKINGGEOMETRYTOOL_H
+#ifndef ACTSGEOMETRYINTERFACES_IACTSTRACKINGGEOMETRYTOOL_H
+#define ACTSGEOMETRYINTERFACES_IACTSTRACKINGGEOMETRYTOOL_H
 
 #include "AthenaBaseComps/AthAlgTool.h"
 #include "GaudiKernel/IInterface.h"
diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsVolumeMappingTool.h b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsVolumeMappingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..b87e46389875efeb50a694586bf3c4acbfcff521
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsVolumeMappingTool.h
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ACTSGEOMETRYINTERFACES_IACTSVOLUMEMAPPINGTOOL_H
+#define ACTSGEOMETRYINTERFACES_IACTSVOLUMEMAPPINGTOOL_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/EventContext.h"
+
+#include "Acts/Material/VolumeMaterialMapper.hpp"
+
+class IFaserActsTrackingGeometryTool;
+
+class IFaserActsVolumeMappingTool : virtual public IAlgTool {
+  public:
+
+  DeclareInterfaceID(IFaserActsVolumeMappingTool, 1, 0);
+
+
+  virtual
+  std::shared_ptr<Acts::VolumeMaterialMapper>
+  mapper() const = 0;
+
+  virtual
+  Acts::VolumeMaterialMapper::State
+  mappingState() const = 0;
+
+  virtual
+  const IFaserActsTrackingGeometryTool*
+  trackingGeometryTool() const = 0;
+
+};
+
+#endif