diff --git a/Algorithms/CMakeLists.txt b/Algorithms/CMakeLists.txt
index 164852425bab8e28c138eb214ee8afe78adb5607..cb73a2e35c638c02777d1e621d5d018aaa45935b 100644
--- a/Algorithms/CMakeLists.txt
+++ b/Algorithms/CMakeLists.txt
@@ -1,5 +1,5 @@
 add_subdirectory(Digitization)
 add_subdirectory(Fatras)
 add_subdirectory(Generators)
-#add_subdirectory_if(MaterialMapping USE_GEANT4)
+add_subdirectory(MaterialMapping)
 add_subdirectory(Propagation)
diff --git a/Algorithms/Digitization/src/DigitizationAlgorithm.cpp b/Algorithms/Digitization/src/DigitizationAlgorithm.cpp
index 94a8d6f392b31602f36a99e4bca1552f11d5efca..d8713f6c88ba1bdcc966106ec1b02513f5172ba8 100644
--- a/Algorithms/Digitization/src/DigitizationAlgorithm.cpp
+++ b/Algorithms/Digitization/src/DigitizationAlgorithm.cpp
@@ -67,16 +67,18 @@ FW::DigitizationAlgorithm::execute(const AlgorithmContext& context) const
   // now digitise
   for (auto& vData : simHits) {
     auto volumeKey = vData.first;
-    ACTS_DEBUG("- Processing Volume Data collection for volume with ID "
-               << volumeKey);
+    ACTS_VERBOSE("- Processing Volume Data collection for volume with ID "
+                 << volumeKey);
     for (auto& lData : vData.second) {
       auto layerKey = lData.first;
-      ACTS_DEBUG("-- Processing Layer Data collection for layer with ID "
-                 << layerKey);
+      ACTS_VERBOSE("-- Processing Layer Data collection for layer with ID "
+                   << layerKey);
       for (auto& sData : lData.second) {
         auto moduleKey = sData.first;
-        ACTS_DEBUG("-- Processing Module Data collection for module with ID "
-                   << moduleKey);
+        ACTS_VERBOSE("-- Processing Module Data collection for module with ID "
+                     << moduleKey);
+        ACTS_VERBOSE("-- Recieved " << sData.second.size()
+                                    << " input data objects.");
         // get the hit parameters
         for (auto& hit : sData.second) {
           // get the surface
@@ -105,7 +107,7 @@ FW::DigitizationAlgorithm::execute(const AlgorithmContext& context) const
               Acts::Vector2D localIntersection(localIntersect3D.x(),
                                                localIntersect3D.y());
               Acts::Vector3D localDirection(invTransfrom.linear()
-                                            * hit.direction);
+                                            * hit.direction.normalized());
               // now calculate the steps through the silicon
               std::vector<Acts::DigitizationStep> dSteps
                   = m_cfg.planarModuleStepper->cellSteps(context.geoContext,
@@ -113,7 +115,10 @@ FW::DigitizationAlgorithm::execute(const AlgorithmContext& context) const
                                                          localIntersection,
                                                          localDirection);
               // everything under threshold or edge effects
-              if (!dSteps.size()) continue;
+              if (!dSteps.size()) {
+                ACTS_VERBOSE("No steps returned from stepper.");
+                continue;
+              }
               /// let' create a cluster - centroid method
               double localX    = 0.;
               double localY    = 0.;
@@ -156,7 +161,6 @@ FW::DigitizationAlgorithm::execute(const AlgorithmContext& context) const
               geoID.add(volumeKey, Acts::GeometryID::volume_mask);
               geoID.add(layerKey, Acts::GeometryID::layer_mask);
               geoID.add(moduleKey, Acts::GeometryID::sensitive_mask);
-              geoID.add(binSerialized, Acts::GeometryID::channel_mask);
 
               // create the planar cluster
               Acts::PlanarModuleCluster pCluster(
diff --git a/Algorithms/Generators/CMakeLists.txt b/Algorithms/Generators/CMakeLists.txt
index 158cd86407bb8c6997c55f14c1fcfbbbc6826114..41b31be8338722244637543ece3957d4061b06d0 100644
--- a/Algorithms/Generators/CMakeLists.txt
+++ b/Algorithms/Generators/CMakeLists.txt
@@ -11,3 +11,4 @@ target_link_libraries(ActsFrameworkGenerators
   PUBLIC ActsCore ACTFramework ${Boost_PROGRAM_OPTIONS_LIBRARY})
 
 install(TARGETS ActsFrameworkGenerators LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
diff --git a/Algorithms/MaterialMapping/CMakeLists.txt b/Algorithms/MaterialMapping/CMakeLists.txt
index 43885f5ebdaa1ab4cf6c5842dcfb622a31c28cc1..63f151b27fbac81ca97d2b67070a74bac52f6cdc 100644
--- a/Algorithms/MaterialMapping/CMakeLists.txt
+++ b/Algorithms/MaterialMapping/CMakeLists.txt
@@ -1,11 +1,16 @@
-include(${Geant4_USE_FILE})
-
-file(GLOB_RECURSE src_files "src/*.cpp" "include/*.*pp")
+file(GLOB_RECURSE src_files "src/MaterialMapping.cpp")
+if (USE_GEANT4)
+  SET(src_files "src/GeantinoRecording.cpp" ${src_files})  
+  include(${Geant4_USE_FILE})  
+endif()
 
 add_library(ACTFWMaterialMapping SHARED ${src_files})
 target_include_directories(ACTFWMaterialMapping PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/> $<INSTALL_INTERFACE:include>)
 target_link_libraries(ACTFWMaterialMapping PUBLIC ActsCore ActsMaterialMappingPlugin)
-target_link_libraries(ACTFWMaterialMapping PUBLIC ACTFramework ACTFWGeant4Plugin)
+target_link_libraries(ACTFWMaterialMapping PUBLIC ACTFramework)
+if (USE_GEANT4)
+  target_link_libraries(ACTFWMaterialMapping PUBLIC ACTFWGeant4Plugin ACTFWGeometryInterfaces)
+endif()
 
 install(TARGETS ACTFWMaterialMapping LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
 install(DIRECTORY include/ACTFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
diff --git a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/GeantinoRecording.hpp b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/GeantinoRecording.hpp
index 7f0e0a5255e8123a09e99ecf8f31a885636d2e2e..64b433c0bc07c2e1eb23d3856c8cdf530f7caddb 100644
--- a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/GeantinoRecording.hpp
+++ b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/GeantinoRecording.hpp
@@ -6,24 +6,32 @@
 // 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/.
 
-#ifndef ACTW_ALGORITHMS_MATERIALMAPPING_GEANTINORECORDING_H
-#define ACTW_ALGORITHMS_MATERIALMAPPING_GEANTINORECORDING_H
+#pragma once
 
 #include <memory>
 #include "ACTFW/Framework/BareAlgorithm.hpp"
 #include "ACTFW/Framework/ProcessCode.hpp"
 #include "ACTFW/GeometryInterfaces/IGeant4Service.hpp"
-#include "ACTFW/Writers/IWriterT.hpp"
-#include "Acts/Plugins/MaterialMapping/MaterialTrack.hpp"
+#include "Acts/Extrapolator/MaterialInteractor.hpp"
+#include "Acts/Utilities/Definitions.hpp"
 #include "Acts/Utilities/Logger.hpp"
 #include "G4RunManager.hh"
 
-namespace FW {
-class WhiteBoard;
+namespace Acts {
+// Using some short hands for Recorded Material
+using RecordedMaterial = MaterialInteractor::result_type;
+
+// And recorded material track
+// - this is start:  position, start momentum
+//   and the Recorded material
+using RecordedMaterialTrack
+    = std::pair<std::pair<Acts::Vector3D, Acts::Vector3D>, RecordedMaterial>;
 }
 
 namespace FW {
 
+class WhiteBoard;
+
 /// @class GeantinoRecording
 ///
 /// @brief records the simulation geometry by using geantinos
@@ -40,16 +48,17 @@ public:
   /// @class Config
   struct Config
   {
-    /// The writer writing out the MaterialTrack entities
-    std::shared_ptr<FW::IWriterT<Acts::MaterialTrack>> materialTrackWriter
-        = nullptr;
+    std::string geantMaterialCollection = "geant-material-tracks";
+
     /// The service possibly providing the Geant4 geometry (optional)
     /// @note If this is not set, the geometry should be given by gdml file
     std::shared_ptr<FW::IGeant4Service> geant4Service = nullptr;
+
     /// The possible gmdl input (optional)
     std::string gdmlFile;
     /// The number of tracks per event
     size_t tracksPerEvent = 0;
+
     /// random number seed 1
     int seed1 = 12345;
     /// random number seed 2
@@ -70,5 +79,3 @@ private:
   std::unique_ptr<G4RunManager> m_runManager;
 };
 }
-
-#endif  // ACTW_ALGORITHMS_GEANTINORECORDING_H
diff --git a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/IMaterialWriter.hpp b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/IMaterialWriter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..98fab012d3cb51880f7ad7413270ff9177e0941c
--- /dev/null
+++ b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/IMaterialWriter.hpp
@@ -0,0 +1,74 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2019 Acts project team
+//
+// 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 <map>
+#include "Acts/Utilities/GeometryID.hpp"
+
+namespace Acts {
+
+class ISurfaceMaterial;
+class IVolumeMaterial;
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+
+using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
+}
+
+namespace FW {
+
+/// @class IMaterialWriter
+///
+/// Interface definition for material writing
+class IMaterialWriter
+{
+public:
+  /// Virtual Destructor
+  virtual ~IMaterialWriter() = default;
+
+  /// The single wirter class
+  ///
+  /// @param detMaterial the detector material maps
+  virtual void
+  writeMaterial(const Acts::DetectorMaterialMaps& detMaterial)
+      = 0;
+};
+
+/// @class MaterialWriterT
+///
+/// @tparam writer_t is the actual implementation
+template <typename writer_t>
+class MaterialWriterT : virtual public IMaterialWriter
+{
+public:
+  /// Constructor
+  ///
+  /// @tparam writer_t the templated writer implementation
+  ///
+  /// @param impl the actaul implementation of the writer
+  MaterialWriterT(writer_t impl) : m_impl(std::move(impl)) {}
+
+  /// The single wirter class
+  ///
+  /// @param detMaterial the detector material maps
+  void
+  writeMaterial(const Acts::DetectorMaterialMaps& detMaterial)
+  {
+    m_impl.write(detMaterial);
+  }
+
+private:
+  /// The writer implementation
+  writer_t m_impl;
+};
+}
diff --git a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp
index ecd719027f05c99f94de1b78a5a6fd431fd3c472..c5d3dbe69254678ee7e95e9d96b6182f7353eb23 100644
--- a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp
+++ b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp
@@ -1,47 +1,55 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2019 Acts project team
 //
 // 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/.
 
-#ifndef ACTFW_ALGORITHMS_MATERIALMAPPING_MATERIALMAPPING_H
-#define ACTFW_ALGORITHMS_MATERIALMAPPING_MATERIALMAPPING_H
+#pragma once
 
 #include <climits>
 #include <memory>
+#include <mutex>
 
 #include "ACTFW/Framework/BareAlgorithm.hpp"
 #include "ACTFW/Framework/ProcessCode.hpp"
-#include "ACTFW/Readers/IReaderT.hpp"
-#include "ACTFW/Writers/IWriterT.hpp"
-#include "Acts/Layers/Layer.hpp"
-#include "Acts/Material/SurfaceMaterial.hpp"
-#include "Acts/Plugins/MaterialMapping/MaterialMapper.hpp"
-#include "Acts/Plugins/MaterialMapping/MaterialTrack.hpp"
+#include "ACTFW/MaterialMapping/IMaterialWriter.hpp"
+#include "Acts/Plugins/MaterialMapping/SurfaceMaterialMapper.hpp"
 #include "Acts/Utilities/Logger.hpp"
 
-namespace FW {
-class WhiteBoard;
-}
-
 namespace Acts {
+
 class TrackingGeometry;
+class ISurfaceMaterial;
+class IVolumeMaterial;
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+
+using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
 }
 
 namespace FW {
 
 /// @class MaterialMapping
 ///
-/// @brief Initiates material mapping
+/// @brief Initiates and executes material mapping
 ///
 /// The MaterialMapping reads in the MaterialTrack with a dedicated
 /// reader and uses the material mapper to project the material onto
 /// the tracking geometry
 ///
-/// In a final step, the material maps are written out for further usage
-
+/// By construction, the material mapping needs inter-event information
+/// to build the material maps of accumulated single particle views.
+/// However, running it in one single event, puts enormous pressure onto
+/// the I/O structure.
+///
+/// It therefore saves the mapping state/cache as a private member variable
+/// and is designed to be executed in a single threaded mode.
 class MaterialMapping : public FW::BareAlgorithm
 {
 public:
@@ -49,36 +57,53 @@ public:
   /// of the MaterialMapping algorithm
   struct Config
   {
-  public:
-    /// The reader to read in the MaterialTrack entities
-    std::shared_ptr<FW::IReaderT<Acts::MaterialTrack>> materialTrackReader
-        = nullptr;
-    /// The ACTS material mapper
-    std::shared_ptr<Acts::MaterialMapper> materialMapper = nullptr;
-    /// The validation writer of the material
-    std::shared_ptr<FW::IWriterT<Acts::MaterialTrack>> materialTrackWriter
-        = nullptr;
+    /// Constructor with geometry and magnetic field contexts
+    Config(std::reference_wrapper<const Acts::GeometryContext>      gctx,
+           std::reference_wrapper<const Acts::MagneticFieldContext> mctx)
+      : geoContext(gctx), magFieldContext(mctx)
+    {
+    }
+
+    /// Input collection
+    std::string collection = "material-tracks";
+
+    /// The ACTS surface material mapper
+    std::shared_ptr<Acts::SurfaceMaterialMapper> materialMapper = nullptr;
+
     /// The writer of the material
-    std::shared_ptr<FW::IWriterT<Acts::IndexedSurfaceMaterial>>
-        indexedMaterialWriter = nullptr;
+    std::vector<std::shared_ptr<IMaterialWriter>> materialWriters;
+
     /// The TrackingGeometry to be mapped on
     std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry = nullptr;
-    /// mapping conditions
-    size_t maximumTrackRecords = std::numeric_limits<size_t>::infinity();
+
+    // Geometry context for the state creation
+    std::reference_wrapper<const Acts::GeometryContext> geoContext;
+
+    // MagneticField  context for the state creation
+    std::reference_wrapper<const Acts::MagneticFieldContext> magFieldContext;
   };
 
   /// Constructor
+  ///
+  /// @param cfg The configuration struct carrying the used tools
+  /// @param level The output logging level
   MaterialMapping(const Config&        cfg,
                   Acts::Logging::Level level = Acts::Logging::INFO);
 
+  /// Destructor
+  /// - it also writes out the file
+  ~MaterialMapping();
+
   /// Framework execute method
+  ///
+  /// @param context The algorithm context for event consistency
   FW::ProcessCode
   execute(const AlgorithmContext& context) const final override;
 
 private:
-  Config m_cfg;
+  Config m_cfg;  //!< internal config object
+  Acts::SurfaceMaterialMapper::State
+      m_mappingState;  //!< Material mapping state
 };
 
 }  // namespace FW
-
-#endif  // ACTFW_ALGORITHMS_MATERIALMAPPING_MATERIALMAPPING_H
diff --git a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMappingOptions.hpp b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMappingOptions.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..84239ea5f94f29f4a3c735e02a1ffd807ff63964
--- /dev/null
+++ b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMappingOptions.hpp
@@ -0,0 +1,57 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2019 Acts project team
+//
+// 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 <iostream>
+#include "ACTFW/Utilities/Options.hpp"
+#include "Acts/Utilities/Units.hpp"
+
+namespace po = boost::program_options;
+
+namespace FW {
+
+namespace Options {
+
+  /// @brief Material mapping options, specially added
+  ///
+  /// @tparam aopt_t Type of the options object (API bound to boost)
+  ///
+  /// @param [in] opt_t The options object where the specific digitization
+  /// options are attached to
+  template <typename aopt_t>
+  void
+  addMaterialMappingOptions(aopt_t& opt)
+  {
+    opt.add_options()(
+        "mat-mapping-collection",
+        po::value<std::string>()->default_value("material-tracks"),
+        "Collection name of the material tracks for reading.");
+  }
+
+  ///@brief  Read the digitization options and return a Config object
+  ///
+  ///@tparam omap_t Type of the options map
+  ///@param vm the options map to be read out
+  // template <typename omap_t>
+  // DigitizationAlgorithm::Config
+  // readDigitizationConfig(const omap_t& vm)
+  //{
+  //  // create a config
+  //  DigitizationAlgorithm::Config digiConfig;
+  //  digiConfig.spacePointCollection
+  //      = vm["digi-spacepoints"].template as<std::string>();
+  //  digiConfig.clusterCollection
+  //      = vm["digi-clusters"].template as<std::string>();
+  //  digiConfig.resolutionFile
+  //      = vm["digi-resolution-file"].template as<std::string>();
+  //  // and return the config
+  //  return digiConfig;
+  //}
+}  // namespace Options
+}  // namespace FW
\ No newline at end of file
diff --git a/Algorithms/MaterialMapping/src/GeantinoRecording.cpp b/Algorithms/MaterialMapping/src/GeantinoRecording.cpp
index a1ae1d92161ce8ab1eec5b5db1a79e6b346d010f..e46731f9a853bf377ad595156262784a8ceff1bb 100644
--- a/Algorithms/MaterialMapping/src/GeantinoRecording.cpp
+++ b/Algorithms/MaterialMapping/src/GeantinoRecording.cpp
@@ -1,6 +1,6 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2018 Acts project team
 //
 // 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
@@ -9,6 +9,7 @@
 #include "ACTFW/MaterialMapping/GeantinoRecording.hpp"
 #include <iostream>
 #include <stdexcept>
+#include "ACTFW/Framework/WhiteBoard.hpp"
 #include "ACTFW/Plugins/Geant4/MMDetectorConstruction.hpp"
 #include "ACTFW/Plugins/Geant4/MMEventAction.hpp"
 #include "ACTFW/Plugins/Geant4/MMPrimaryGeneratorAction.hpp"
@@ -23,11 +24,6 @@ FW::GeantinoRecording::GeantinoRecording(
   , m_cfg(cnf)
   , m_runManager(std::make_unique<G4RunManager>())
 {
-  /// Make sure that a writer was provided in the configuration
-  if (!m_cfg.materialTrackWriter) {
-    throw std::invalid_argument("Missing material track writer");
-  }
-
   /// Check if the geometry should be accessed over the geant4 service
   if (m_cfg.geant4Service) {
     m_runManager->SetUserInitialization(m_cfg.geant4Service->geant4Geometry());
@@ -35,8 +31,8 @@ FW::GeantinoRecording::GeantinoRecording(
     /// Access the geometry from the gdml file
     ACTS_INFO(
         "received Geant4 geometry from GDML file: " << m_cfg.gdmlFile.c_str());
-    FW::G4::MMDetectorConstruction* detConstruction
-        = new FW::G4::MMDetectorConstruction();
+    FW::Geant4::MMDetectorConstruction* detConstruction
+        = new FW::Geant4::MMDetectorConstruction();
     detConstruction->setGdmlInput(m_cfg.gdmlFile.c_str());
     m_runManager->SetUserInitialization(
         detConstruction);  // constructs detector (calls Construct in
@@ -47,30 +43,30 @@ FW::GeantinoRecording::GeantinoRecording(
 
   /// Now set up the Geant4 simulation
   m_runManager->SetUserInitialization(new FTFP_BERT);
-  m_runManager->SetUserAction(new FW::G4::MMPrimaryGeneratorAction(
+  m_runManager->SetUserAction(new FW::Geant4::MMPrimaryGeneratorAction(
       "geantino", 1000., m_cfg.seed1, m_cfg.seed2));
-  FW::G4::MMRunAction* runaction = new FW::G4::MMRunAction();
+  FW::Geant4::MMRunAction* runaction = new FW::Geant4::MMRunAction();
   m_runManager->SetUserAction(runaction);
-  m_runManager->SetUserAction(new FW::G4::MMEventAction());
-  m_runManager->SetUserAction(new FW::G4::MMSteppingAction());
+  m_runManager->SetUserAction(new FW::Geant4::MMEventAction());
+  m_runManager->SetUserAction(new FW::Geant4::MMSteppingAction());
   m_runManager->Initialize();
 }
 
 FW::ProcessCode
-FW::GeantinoRecording::execute(const FW::AlgorithmContext&) const
+FW::GeantinoRecording::execute(const FW::AlgorithmContext& context) const
 {
 
-  /// Begin with the simulation
+  // Begin with the simulation
   m_runManager->BeamOn(m_cfg.tracksPerEvent);
-  ///
-  std::vector<Acts::MaterialTrack> mtrecords
-      = FW::G4::MMEventAction::Instance()->MaterialTracks();
-  ACTS_INFO("Received " << mtrecords.size()
+  // Retrieve the track material tracks from Geant4
+  auto recordedMaterial
+      = FW::Geant4::MMEventAction::Instance()->MaterialTracks();
+  ACTS_INFO("Received " << recordedMaterial.size()
                         << " MaterialTracks. Writing them now onto file...");
-  // write to the file
-  for (auto& record : mtrecords) {
-    m_cfg.materialTrackWriter->write(record);
-  }
+
+  // Write the recorded material to the event store
+  context.eventStore.add(m_cfg.geantMaterialCollection,
+                         std::move(recordedMaterial));
 
   return FW::ProcessCode::SUCCESS;
 }
diff --git a/Algorithms/MaterialMapping/src/MaterialMapping.cpp b/Algorithms/MaterialMapping/src/MaterialMapping.cpp
index 791ff6600d1e379a85fb68697021881959911e73..9954eab9c598553600ee2d96a51aeba116204da5 100644
--- a/Algorithms/MaterialMapping/src/MaterialMapping.cpp
+++ b/Algorithms/MaterialMapping/src/MaterialMapping.cpp
@@ -1,6 +1,6 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2019 Acts project team
 //
 // 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
@@ -10,78 +10,66 @@
 // MaterialMapping.cpp
 ///////////////////////////////////////////////////////////////////
 
+#include "ACTFW/MaterialMapping/MaterialMapping.hpp"
 #include <iostream>
 #include <stdexcept>
-
-#include <TTree.h>
-
-#include "ACTFW/MaterialMapping/MaterialMapping.hpp"
-#include "Acts/Plugins/MaterialMapping/MaterialTrack.hpp"
-#include "Acts/Plugins/MaterialMapping/SurfaceMaterialRecord.hpp"
+#include "ACTFW/Framework/WhiteBoard.hpp"
 
 FW::MaterialMapping::MaterialMapping(const FW::MaterialMapping::Config& cnf,
                                      Acts::Logging::Level               level)
-  : FW::BareAlgorithm("MaterialMapping", level), m_cfg(cnf)
+  : FW::BareAlgorithm("MaterialMapping", level)
+  , m_cfg(cnf)
+  , m_mappingState(cnf.geoContext, cnf.magFieldContext)
 {
-  if (!m_cfg.materialTrackReader) {
-    throw std::invalid_argument("Missing material track reader");
-  } else if (!m_cfg.materialMapper) {
+  if (!m_cfg.materialMapper) {
     throw std::invalid_argument("Missing material mapper");
-  } else if (!m_cfg.materialTrackWriter) {
-    throw std::invalid_argument("Missing material track writer");
-  } else if (!m_cfg.indexedMaterialWriter) {
-    throw std::invalid_argument("Missing indexed material writer");
   } else if (!m_cfg.trackingGeometry) {
     throw std::invalid_argument("Missing tracking geometry");
   }
+
+  ACTS_INFO("This algorithm requires inter-event information, "
+            << "run in single-threaded mode!");
+
+  // Generate and retrieve the central cache object
+  m_mappingState = m_cfg.materialMapper->createState(
+      m_cfg.geoContext, m_cfg.magFieldContext, *m_cfg.trackingGeometry);
 }
 
-FW::ProcessCode
-    FW::MaterialMapping::execute(FW::AlgorithmContext /*context*/) const
+FW::MaterialMapping::~MaterialMapping()
 {
-  // retrive a cache object
-  Acts::MaterialMapper::Cache mCache
-      = m_cfg.materialMapper->materialMappingCache(*m_cfg.trackingGeometry);
 
-  // access the tree and read the records
-  Acts::MaterialTrack inputTrack;
+  // Finalize all the maps using the cached state
+  m_cfg.materialMapper->finalizeMaps(m_mappingState);
 
-  for (size_t itc = 0;
-       m_cfg.materialTrackReader->read(inputTrack) != FW::ProcessCode::ABORT;
-       ++itc) {
-    ACTS_VERBOSE("Read MaterialTrack " << itc << " from file, it has "
-                                       << inputTrack.materialSteps().size()
-                                       << " steps.");
+  Acts::DetectorMaterialMaps detectorMaterial;
 
-    // some screen output to know what is going on
-    ACTS_VERBOSE("These will be mapped onto "
-                 << mCache.surfaceMaterialRecords.size()
-                 << " surfaces.");
+  // Loop over the state, and collect the maps for surfaces
+  for (auto & [ key, value ] : m_mappingState.surfaceMaterial) {
+    detectorMaterial.first.insert({key, std::move(value)});
+  }
 
-    // perform the mapping
-    auto mappedTrack
-        = m_cfg.materialMapper->mapMaterialTrack(mCache, inputTrack);
+  // Loop over the available writers and write the maps
+  for (auto& imw : m_cfg.materialWriters) {
+    imw->writeMaterial(detectorMaterial);
+  }
+}
 
-    // write out the material for validation purpose
-    m_cfg.materialTrackWriter->write(mappedTrack);
+FW::ProcessCode
+FW::MaterialMapping::execute(const FW::AlgorithmContext& context) const
+{
 
-    // break if configured
-    if (m_cfg.maximumTrackRecords > 0 && itc > m_cfg.maximumTrackRecords) {
-      ACTS_VERBOSE("Maximum track records reached. Stopping.");
-      break;
-    }
-  }
-  /// get the maps back
-  std::map<Acts::GeometryID, Acts::SurfaceMaterial*> sMaterialMaps
-      = m_cfg.materialMapper->createSurfaceMaterial(mCache);
+  // Write to the collection to the EventStore
+  const auto& mtrackCollection
+      = context.eventStore.get<std::vector<Acts::RecordedMaterialTrack>>(
+          m_cfg.collection);
+
+  // To make it work with the framework needs a lock guard
+  auto mappingState
+      = const_cast<Acts::SurfaceMaterialMapper::State*>(&m_mappingState);
 
-  //// write the maps out to a file
-  ACTS_INFO("Writing out the material maps for " << sMaterialMaps.size()
-                                                 << " material surfaces");
-  // loop over the material maps
-  for (auto& sMap : sMaterialMaps) {
-    // write out map by map
-    m_cfg.indexedMaterialWriter->write(sMap);
+  for (auto mTrack : mtrackCollection) {
+    // Map this one onto the geometry
+    m_cfg.materialMapper->mapMaterialTrack(*mappingState, mTrack);
   }
 
   return FW::ProcessCode::SUCCESS;
diff --git a/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.hpp b/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.hpp
index 8020b10d836eeedf2376eeb8fcadcf3a16d45787..903e5487e31b70023f1bcd6eea10f81e60a65867 100644
--- a/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.hpp
+++ b/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.hpp
@@ -12,24 +12,39 @@
 #include <limits>
 #include <memory>
 
-#include <Acts/EventData/NeutralParameters.hpp>
-#include <Acts/EventData/TrackParameters.hpp>
-#include <Acts/Extrapolator/Navigator.hpp>
-#include <Acts/Propagator/AbortList.hpp>
-#include <Acts/Propagator/ActionList.hpp>
-#include <Acts/Propagator/Propagator.hpp>
-#include <Acts/Propagator/detail/DebugOutputActor.hpp>
-#include <Acts/Propagator/detail/StandardAborters.hpp>
-#include <Acts/Propagator/detail/SteppingLogger.hpp>
-#include <Acts/Surfaces/PerigeeSurface.hpp>
-#include <Acts/Utilities/Definitions.hpp>
-#include <Acts/Utilities/Helpers.hpp>
-#include <Acts/Utilities/Units.hpp>
-
 #include "ACTFW/Framework/BareAlgorithm.hpp"
 #include "ACTFW/Framework/ProcessCode.hpp"
 #include "ACTFW/Framework/WhiteBoard.hpp"
 #include "ACTFW/Random/RandomNumbersSvc.hpp"
+#include "Acts/EventData/NeutralParameters.hpp"
+#include "Acts/EventData/TrackParameters.hpp"
+#include "Acts/Extrapolator/MaterialInteractor.hpp"
+#include "Acts/Extrapolator/Navigator.hpp"
+#include "Acts/Propagator/AbortList.hpp"
+#include "Acts/Propagator/ActionList.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/detail/DebugOutputActor.hpp"
+#include "Acts/Propagator/detail/StandardAborters.hpp"
+#include "Acts/Propagator/detail/SteppingLogger.hpp"
+#include "Acts/Surfaces/PerigeeSurface.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/Helpers.hpp"
+#include "Acts/Utilities/Units.hpp"
+
+namespace FW {
+
+/// Using some short hands for Recorded Material
+using RecordedMaterial = Acts::MaterialInteractor::result_type;
+
+/// And recorded material track
+/// - this is start:  position, start momentum
+///   and the Recorded material
+using RecordedMaterialTrack
+    = std::pair<std::pair<Acts::Vector3D, Acts::Vector3D>, RecordedMaterial>;
+
+/// Finally the output of the propagation test
+using PropagationOutput
+    = std::pair<std::vector<Acts::detail::Step>, RecordedMaterial>;
 
 /// @brief this test algorithm performs test propagation
 /// within the Acts::Propagator
@@ -38,8 +53,6 @@
 /// also be used to test the Extrapolator within the geomtetry
 ///
 /// @tparam propagator_t Type of the Propagator to be tested
-namespace FW {
-
 template <typename propagator_t>
 class PropagationAlgorithm : public BareAlgorithm
 {
@@ -59,6 +72,13 @@ public:
     int mode = 0;
     /// debug output
     bool debugOutput = false;
+    /// Modify the behavior of the material interaction: energy loss
+    bool energyLoss = false;
+    /// Modify the behavior of the material interaction: scattering
+    bool multipleScattering = false;
+    /// Modify the behavior of the material interaction: record
+    bool recordMaterialInteractions = false;
+
     /// number of particles
     size_t ntests = 100;
     /// d0 gaussian sigma
@@ -81,6 +101,9 @@ public:
     /// the step collection to be stored
     std::string propagationStepCollection = "PropagationSteps";
 
+    /// The material collection to be stored
+    std::string propagationMaterialCollection = "RecordedMaterialTracks";
+
     /// covariance transport
     bool covarianceTransport = true;
 
@@ -123,7 +146,7 @@ private:
   ///
   /// @return collection of Propagation steps for further analysis
   template <typename parameters_t>
-  std::vector<Acts::detail::Step>
+  PropagationOutput
   executeTest(const AlgorithmContext& context,
               const parameters_t&     startParameters,
               double pathLength = std::numeric_limits<double>::max()) const;
diff --git a/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.ipp b/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.ipp
index 1da718276199b24d6387431ef75a1f1325be4a67..98280a2d0778763f6e9cb49671e8c5ef83a9ab0f 100644
--- a/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.ipp
+++ b/Algorithms/Propagation/include/ACTFW/Propagation/PropagationAlgorithm.ipp
@@ -43,10 +43,12 @@ PropagationAlgorithm<propagator_t>::PropagationAlgorithm(
 
 /// Templated execute test method for
 /// charged and netural particles
+/// @param [in] context is the contextual data of this event
 /// @param [in] startParameters the start parameters
+/// @param [in] pathLength the maximal path length to go
 template <typename propagator_t>
 template <typename parameters_t>
-std::vector<Acts::detail::Step>
+PropagationOutput
 PropagationAlgorithm<propagator_t>::executeTest(
     const AlgorithmContext& context,
     const parameters_t&     startParameters,
@@ -55,16 +57,20 @@ PropagationAlgorithm<propagator_t>::executeTest(
 
   ACTS_DEBUG("Test propagation/extrapolation starts");
 
+  PropagationOutput pOutput;
+
   // This is the outside in mode
   if (m_cfg.mode == 0) {
 
     // The step length logger for testing & end of world aborter
-    using SteppingLogger = Acts::detail::SteppingLogger;
-    using DebugOutput    = Acts::detail::DebugOutputActor;
-    using EndOfWorld     = Acts::detail::EndOfWorldReached;
+    using MaterialInteractor = Acts::MaterialInteractor;
+    using SteppingLogger     = Acts::detail::SteppingLogger;
+    using DebugOutput        = Acts::detail::DebugOutputActor;
+    using EndOfWorld         = Acts::detail::EndOfWorldReached;
 
     // Action list and abort list
-    using ActionList        = Acts::ActionList<SteppingLogger, DebugOutput>;
+    using ActionList
+        = Acts::ActionList<SteppingLogger, MaterialInteractor, DebugOutput>;
     using AbortList         = Acts::AbortList<EndOfWorld>;
     using PropagatorOptions = Acts::PropagatorOptions<ActionList, AbortList>;
 
@@ -77,6 +83,12 @@ PropagationAlgorithm<propagator_t>::executeTest(
         = (Acts::VectorHelpers::perp(startParameters.momentum())
            < m_cfg.ptLoopers);
 
+    // Switch the material interaction on/off & eventually into logging mode
+    auto& mInteractor = options.actionList.get<MaterialInteractor>();
+    mInteractor.multipleScattering = m_cfg.multipleScattering;
+    mInteractor.energyLoss         = m_cfg.energyLoss;
+    mInteractor.recordInteractions = m_cfg.recordMaterialInteractions;
+
     // Set a maximum step size
     options.maxStepSize = m_cfg.maxStepSize;
 
@@ -85,14 +97,22 @@ PropagationAlgorithm<propagator_t>::executeTest(
         = m_cfg.propagator.propagate(startParameters, options).value();
     auto steppingResults = result.template get<SteppingLogger::result_type>();
 
-    if (m_cfg.debugOutput) {
-      auto debugOutput = result.template get<DebugOutput::result_type>();
-      ACTS_VERBOSE(debugOutput.debugString);
+    // Set the stepping result
+    pOutput.first = std::move(steppingResults.steps);
+    // Also set the material recording result - if configured
+    if (m_cfg.recordMaterialInteractions) {
+      auto materialResult
+          = result.template get<MaterialInteractor::result_type>();
+      pOutput.second = std::move(materialResult);
     }
 
-    return steppingResults.steps;
+    // screen output if requested
+    if (m_cfg.debugOutput) {
+      auto& debugResult = result.template get<DebugOutput::result_type>();
+      ACTS_VERBOSE(debugResult.debugString);
+    }
   }
-  return std::vector<Acts::detail::Step>();
+  return pOutput;
 }
 
 template <typename propagator_t>
@@ -118,9 +138,16 @@ PropagationAlgorithm<propagator_t>::execute(
       = Acts::Surface::makeShared<Acts::PerigeeSurface>(
           Acts::Vector3D(0., 0., 0.));
 
+  // Output : the propagation steps
   std::vector<std::vector<Acts::detail::Step>> propagationSteps;
   propagationSteps.reserve(m_cfg.ntests);
 
+  // Output (optional): the recorded material
+  std::vector<RecordedMaterialTrack> recordedMaterial;
+  if (m_cfg.recordMaterialInteractions) {
+    recordedMaterial.reserve(m_cfg.ntests);
+  }
+
   // loop over number of particles
   for (size_t it = 0; it < m_cfg.ntests; ++it) {
     /// get the d0 and z0
@@ -139,27 +166,53 @@ PropagationAlgorithm<propagator_t>::execute(
     // some screen output
     std::unique_ptr<Acts::ActsSymMatrixD<5>> cov = nullptr;
 
+    Acts::Vector3D sPosition(0., 0., 0.);
+    Acts::Vector3D sMomentum(0., 0., 0.);
+
     // execute the test for charged particles
-    std::vector<Acts::detail::Step> testSteps;
+    PropagationOutput pOutput;
     if (charge) {
       // charged extrapolation - with hit recording
       Acts::BoundParameters startParameters(
           context.geoContext, std::move(cov), std::move(pars), surface);
-      testSteps = executeTest<Acts::TrackParameters>(context, startParameters);
+      sPosition = startParameters.position();
+      sMomentum = startParameters.momentum();
+      pOutput   = executeTest<Acts::TrackParameters>(context, startParameters);
     } else {
       // execute the test for neeutral particles
       Acts::NeutralBoundParameters neutralParameters(
           context.geoContext, std::move(cov), std::move(pars), surface);
-      testSteps
+      sPosition = neutralParameters.position();
+      sMomentum = neutralParameters.momentum();
+      pOutput
           = executeTest<Acts::NeutralParameters>(context, neutralParameters);
     }
-    propagationSteps.push_back(testSteps);
+    // Record the propagator steps
+    propagationSteps.push_back(std::move(pOutput.first));
+    if (m_cfg.recordMaterialInteractions
+        && pOutput.second.materialInteractions.size()) {
+      // Create a recorded material track
+      RecordedMaterialTrack rmTrack;
+      // Start position
+      rmTrack.first.first = std::move(sPosition);
+      // Start momentum
+      rmTrack.first.second = std::move(sMomentum);
+      // The material
+      rmTrack.second = std::move(pOutput.second);
+      // push it it
+      recordedMaterial.push_back(std::move(rmTrack));
+    }
   }
 
-  // write simulated data to the event store
-  // - the simulated particles
+  // Write the propagation step data to the event store
   context.eventStore.add(m_cfg.propagationStepCollection,
                          std::move(propagationSteps));
 
+  // Write the recorded material to the event store
+  if (m_cfg.recordMaterialInteractions) {
+    context.eventStore.add(m_cfg.propagationMaterialCollection,
+                           std::move(recordedMaterial));
+  }
+
   return ProcessCode::SUCCESS;
 }
diff --git a/Algorithms/Propagation/include/ACTFW/Propagation/PropagationOptions.hpp b/Algorithms/Propagation/include/ACTFW/Propagation/PropagationOptions.hpp
index 581b8611f2b6a98f5a8e29b3d1440c04fa27281f..71745d434e0645956af673187f3e97fcc0daf490 100644
--- a/Algorithms/Propagation/include/ACTFW/Propagation/PropagationOptions.hpp
+++ b/Algorithms/Propagation/include/ACTFW/Propagation/PropagationOptions.hpp
@@ -50,6 +50,12 @@ namespace Options {
         "prop-scattering",
         po::value<bool>()->default_value(true),
         "Apply scattering correction - in extrapolation mode only.")(
+        "prop-record-material",
+        po::value<bool>()->default_value(true),
+        "Record the material interaction and - in extrapolation mode only.")(
+        "prop-material-collection",
+        po::value<std::string>()->default_value("propagation-material"),
+        "Propagation material collection.")(
         "prop-ntests",
         po::value<size_t>()->default_value(1000),
         "Number of tests performed.")(
@@ -70,7 +76,7 @@ namespace Options {
             {100. * au::_MeV, 100. * au::_GeV}),
         "Transverse momentum range for proprapolated tracks [in GeV].")(
         "prop-max-stepsize",
-        po::value<double>()->default_value(1 * au::_m),
+        po::value<double>()->default_value(10 * au::_m),
         "Maximum step size for the propagation [in mm].")(
         "prop-pt-loopers",
         po::value<double>()->default_value(0.3 * au::_GeV),
@@ -99,6 +105,12 @@ namespace Options {
     read_range ietar = vm["prop-eta-range"].template as<read_range>();
     read_range iptr  = vm["prop-pt-range"].template as<read_range>();
 
+    /// Material interaction behavior
+    pAlgConfig.energyLoss         = vm["prop-energyloss"].template as<bool>();
+    pAlgConfig.multipleScattering = vm["prop-scattering"].template as<bool>();
+    pAlgConfig.recordMaterialInteractions
+        = vm["prop-record-material"].template as<bool>();
+
     /// Create the config for the Extrapoaltion algorithm
     pAlgConfig.debugOutput = vm["prop-debug"].template as<bool>();
     pAlgConfig.ntests      = vm["prop-ntests"].template as<size_t>();
@@ -115,6 +127,8 @@ namespace Options {
 
     pAlgConfig.propagationStepCollection
         = vm["prop-step-collection"].template as<std::string>();
+    pAlgConfig.propagationMaterialCollection
+        = vm["prop-material-collection"].template as<std::string>();
 
     return pAlgConfig;
   }
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f0b8eea6353807049c9bb7cb52cc95c8db6ad4d4..ad63bc8dc7d6802d765e928620b72b27db9fa219 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -85,6 +85,7 @@ if(BUILD_ACTS)
   set(ACTS_BUILD_DD4HEP_PLUGIN ${USE_DD4HEP} CACHE BOOL "Build Acts DD4HEP plugin")
   set(ACTS_BUILD_MATERIAL_PLUGIN ON CACHE BOOL "Build Acts Material plugin")
   set(ACTS_BUILD_DIGITIZATION_PLUGIN ON CACHE BOOL "Build Acts Digitization plugin")
+  set(ACTS_BUILD_JSON_PLUGIN ON CACHE BOOL "Build Acts Json plugin")
   set(ACTS_BUILD_TGEO_PLUGIN ${USE_TGEO} CACHE BOOL "Build Acts TGeo plugin")
   set(ACTS_BUILD_IDENTIFICATION_PLUGIN ON CACHE BOOL "Build Acts Identification plugin")
   add_subdirectory(external/acts-core)
diff --git a/Core/include/ACTFW/Random/RandomNumbersSvc.hpp b/Core/include/ACTFW/Random/RandomNumbersSvc.hpp
index d199914dba9bc75ae04d6933c1679680ea907da2..2550327f7f07f6228485df5eb8511e8385db6ce9 100644
--- a/Core/include/ACTFW/Random/RandomNumbersSvc.hpp
+++ b/Core/include/ACTFW/Random/RandomNumbersSvc.hpp
@@ -74,7 +74,7 @@ public:
   RandomEngine
   spawnGenerator(const AlgorithmContext& context) const;
 
-  const unsigned int
+  unsigned int
   generateSeed(const AlgorithmContext& context) const;
 
   /// Ask for the seed
diff --git a/Core/include/ACTFW/Utilities/Paths.hpp b/Core/include/ACTFW/Utilities/Paths.hpp
index 41d00712cb8e287ce55f67d7c7ec1301d29c6497..f0757883b5adf2c700f6ffb17f337c403c94b1cd 100644
--- a/Core/include/ACTFW/Utilities/Paths.hpp
+++ b/Core/include/ACTFW/Utilities/Paths.hpp
@@ -6,13 +6,10 @@
 // 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/.
 
-/// @file
-/// @date 2017-08-03
-/// @author Moritz Kiehnn <msmk@cern.ch>
-
 #pragma once
 
 #include <string>
+#include <vector>
 
 namespace FW {
 
@@ -28,4 +25,11 @@ joinPaths(const std::string& dir, const std::string& name);
 std::string
 perEventFilepath(const std::string& dir, const std::string& name, size_t event);
 
+/// Brief split a file list into a vector of file names to add
+///
+/// @param files The joint file list
+/// @param tag The splitting tag
+std::vector<std::string>
+splitByDelimiter(const std::string& files, char delim);
+
 }  // namespace FW
diff --git a/Core/src/Random/RandomNumbersSvc.cpp b/Core/src/Random/RandomNumbersSvc.cpp
index d1b812d469808d39009661459c8da499e88a6ce3..d528eb3612509bbb5b82b764b8d9240755199bdc 100644
--- a/Core/src/Random/RandomNumbersSvc.cpp
+++ b/Core/src/Random/RandomNumbersSvc.cpp
@@ -35,7 +35,7 @@ FW::RandomNumbersSvc::spawnGenerator(const AlgorithmContext& context) const
   return RandomEngine(generateSeed(context));
 }
 
-const unsigned int
+unsigned int
 FW::RandomNumbersSvc::generateSeed(const AlgorithmContext& context) const
 {
   // use Cantor pairing function to generate a unique generator id from
diff --git a/Core/src/Utilities/Paths.cpp b/Core/src/Utilities/Paths.cpp
index ec81deda8401421a2d484bb2f104acd5b21dcbda..ac6ef521c2826e692a509aaf99cfcced590002a7 100644
--- a/Core/src/Utilities/Paths.cpp
+++ b/Core/src/Utilities/Paths.cpp
@@ -9,6 +9,8 @@
 #include "ACTFW/Utilities/Paths.hpp"
 
 #include <cstdio>
+#include <iostream>
+#include <sstream>
 
 std::string
 FW::joinPaths(const std::string& dir, const std::string& name)
@@ -35,3 +37,16 @@ FW::perEventFilepath(const std::string& dir,
     return dir + '/' + prefix + name;
   }
 }
+
+std::vector<std::string>
+FW::splitByDelimiter(const std::string& files, char delim)
+{
+  std::vector<std::string> fileList;
+
+  std::stringstream ss(files);
+  std::string       token;
+  while (getline(ss, token, delim)) {
+    fileList.push_back(token);
+  }
+  return fileList;
+}
diff --git a/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/AlignedDetector.hpp b/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/AlignedDetector.hpp
index e4f109e3e42e82b5f9426764112fe1bbf1af5f12..5553846a830c02c43be4135e6575e0e6062dc355 100644
--- a/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/AlignedDetector.hpp
+++ b/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/AlignedDetector.hpp
@@ -86,12 +86,15 @@ struct AlignedGeometry
   /// optionally the geometry context decorator(s)
   ///
   /// @tparam variable_map_t Type of the variable map template for parameters
+  /// @tparam material_decorator_t Type of the material decorator
+  ///
   /// @param vm the parameter map object
+  /// @param mdecorator the actual material decorator
   ///
   /// @return a TrackingGeometry object, and optional context decorator(s)
-  template <typename variable_map_t>
+  template <typename variable_map_t, typename material_decorator_t>
   std::pair<TrackingGeometryPtr, ContextDecorators>
-  operator()(variable_map_t& vm)
+  operator()(variable_map_t& vm, material_decorator_t mdecorator)
   {
     // --------------------------------------------------------------------------------
     DetectorElement::ContextType nominalContext;
@@ -105,11 +108,16 @@ struct AlignedGeometry
     Acts::Logging::Level volumeLogLevel
         = Acts::Logging::Level(vm["geo-volume-loglevel"].template as<size_t>());
 
-    /// return the generic detector
+    bool buildProto
+        = (vm["mat-input-type"].template as<std::string>() == "proto");
+
+    /// return the generic detector - with aligned context decorator
     TrackingGeometryPtr aTrackingGeometry
         = FW::Generic::buildDetector<DetectorElement>(nominalContext,
                                                       detectorStore,
                                                       buildLevel,
+                                                      std::move(mdecorator),
+                                                      buildProto,
                                                       surfaceLogLevel,
                                                       layerLogLevel,
                                                       volumeLogLevel);
diff --git a/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/PayloadDetector.hpp b/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/PayloadDetector.hpp
index 13d705ab90b4e649d5afacc86ebcebe9ebe94f72..3d2c72ca20c4d6f911f86f1ab587d1ea8e4d5884 100644
--- a/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/PayloadDetector.hpp
+++ b/Detectors/ContextualDetector/include/ACTFW/ContextualDetector/PayloadDetector.hpp
@@ -63,12 +63,15 @@ struct PayloadGeometry
   /// optionally the geometry context decorator(s)
   ///
   /// @tparam variable_map_t Type of the variable map template for parameters
+  /// @tparam material_decorator_t Type of the material decorator
+  ///
   /// @param vm the parameter map object
+  /// @param mdecorator the actual material decorator
   ///
   /// @return a TrackingGeometry object, and optional context decorator(s)
-  template <typename variable_map_t>
+  template <typename variable_map_t, typename material_decorator_t>
   std::pair<TrackingGeometryPtr, ContextDecorators>
-  operator()(variable_map_t& vm)
+  operator()(variable_map_t& vm, material_decorator_t mdecorator)
   {
     // --------------------------------------------------------------------------------
     DetectorElement::ContextType nominalContext;
@@ -80,11 +83,16 @@ struct PayloadGeometry
     Acts::Logging::Level volumeLogLevel
         = Acts::Logging::Level(vm["geo-volume-loglevel"].template as<size_t>());
 
-    /// return the generic detector
+    bool buildProto
+        = (vm["mat-input-type"].template as<std::string>() == "proto");
+
+    /// return the generic detector - with payload context decorator
     TrackingGeometryPtr pTrackingGeometry
         = FW::Generic::buildDetector<DetectorElement>(nominalContext,
                                                       detectorStore,
                                                       0,
+                                                      std::move(mdecorator),
+                                                      buildProto,
                                                       surfaceLogLevel,
                                                       layerLogLevel,
                                                       volumeLogLevel);
diff --git a/Detectors/DD4hepDetector/include/ACTFW/DD4hepDetector/DD4hepDetector.hpp b/Detectors/DD4hepDetector/include/ACTFW/DD4hepDetector/DD4hepDetector.hpp
index 45a441871a6cd97c2e068328dce54289299049b9..55563c5f347df06588ec7905686ea5f46fea90c6 100644
--- a/Detectors/DD4hepDetector/include/ACTFW/DD4hepDetector/DD4hepDetector.hpp
+++ b/Detectors/DD4hepDetector/include/ACTFW/DD4hepDetector/DD4hepDetector.hpp
@@ -38,12 +38,15 @@ struct DD4hepGeometry
   /// optionally the geometry context decorator(s)
   ///
   /// @tparam variable_map_t Type of the variable map template for parameters
+  /// @tparam material_decorator_t Type of the material decorator
+  ///
   /// @param vm the parameter map object
+  /// @param mdecorator the actual material decorator
   ///
   /// @return a TrackingGeometry object, and optional context decorator(s)
-  template <typename variable_map_t>
+  template <typename variable_map_t, typename material_decorator_t>
   std::pair<TrackingGeometryPtr, ContextDecorators>
-  operator()(variable_map_t& vm)
+  operator()(variable_map_t& vm, material_decorator_t /*mdecorator*/)
   {
     Acts::GeometryContext dd4HepContext;
     // read the detector config & dd4hep detector
diff --git a/Detectors/GenericDetector/include/ACTFW/GenericDetector/BuildGenericDetector.hpp b/Detectors/GenericDetector/include/ACTFW/GenericDetector/BuildGenericDetector.hpp
index fa7e9d259173b0f340ea2a2d81632bdf69b42f71..f9c7774522a6212b29a0c8739455f2d8c840c483 100644
--- a/Detectors/GenericDetector/include/ACTFW/GenericDetector/BuildGenericDetector.hpp
+++ b/Detectors/GenericDetector/include/ACTFW/GenericDetector/BuildGenericDetector.hpp
@@ -19,6 +19,7 @@
 #include "Acts/Detector/TrackingGeometry.hpp"
 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
 #include "Acts/Material/Material.hpp"
+#include "Acts/Material/ProtoSurfaceMaterial.hpp"
 #include "Acts/Tools/CylinderVolumeBuilder.hpp"
 #include "Acts/Tools/CylinderVolumeHelper.hpp"
 #include "Acts/Tools/LayerArrayCreator.hpp"
@@ -27,6 +28,7 @@
 #include "Acts/Tools/SurfaceArrayCreator.hpp"
 #include "Acts/Tools/TrackingGeometryBuilder.hpp"
 #include "Acts/Tools/TrackingVolumeArrayCreator.hpp"
+#include "Acts/Utilities/BinUtility.hpp"
 #include "Acts/Utilities/Definitions.hpp"
 #include "Acts/Utilities/Logger.hpp"
 #include "Acts/Utilities/Units.hpp"
@@ -90,22 +92,28 @@ namespace Generic {
   /// element, each derivative of a GenericDetectorElement can be used
   ///
   /// @param gctx is the detector element dependent geometry context
-  /// @param surfaceLLevel is the surface building logging level
-  /// @param layerLLevel is the layer building logging level
-  /// @param volumeLLevel is the volume building logging level
   /// @param detectorStore is the store for the detector element
+  /// @param matDecorator is an optional decorator for the material
   /// @param level is the detector building level
   ///          0 - pixel barrel only
   ///          1 - pixel detector only
   ///          2 - full barrel only
   ///          3 - full detector (without stereo modules)
+  /// @param matDecorator is the source for material decoration
+  /// @param protoMaterial is a flag to steer proto material to be loaded
+  /// @param surfaceLLevel is the surface building logging level
+  /// @param layerLLevel is the layer building logging level
+  /// @param volumeLLevel is the volume building logging level
   /// return a unique vector to the tracking geometry
   template <typename detector_element_t>
   std::unique_ptr<const Acts::TrackingGeometry>
   buildDetector(const typename detector_element_t::ContextType& gctx,
                 std::vector<std::vector<std::shared_ptr<detector_element_t>>>&
-                                     detectorStore,
-                size_t               level,
+                                                                detectorStore,
+                size_t                                          level,
+                std::shared_ptr<const Acts::IMaterialDecorator> matDecorator
+                = nullptr,
+                bool                 protoMaterial = false,
                 Acts::Logging::Level surfaceLLevel = Acts::Logging::INFO,
                 Acts::Logging::Level layerLLevel   = Acts::Logging::INFO,
                 Acts::Logging::Level volumeLLevel  = Acts::Logging::INFO)
@@ -148,18 +156,40 @@ namespace Generic {
     std::vector<std::shared_ptr<const Acts::ITrackingVolumeBuilder>>
         volumeBuilders;
 
+    // Prepare the proto material - in case it's desinged to do so
+    // - cylindrical
+    Acts::BinUtility pCylinderUtility(10, -1, 1, Acts::closed, Acts::binPhi);
+    pCylinderUtility += Acts::BinUtility(10, -1, 1, Acts::open, Acts::binZ);
+    auto pCylinderMaterial
+        = std::make_shared<const Acts::ProtoSurfaceMaterial>(pCylinderUtility);
+    // - disc
+    Acts::BinUtility pDiscUtility(10, 0, 1, Acts::open, Acts::binR);
+    pDiscUtility += Acts::BinUtility(10, -1, 1, Acts::closed, Acts::binPhi);
+    auto pDiscMaterial
+        = std::make_shared<const Acts::ProtoSurfaceMaterial>(pDiscUtility);
+    // - plane
+    Acts::BinUtility pPlaneUtility(1, -1, 1, Acts::open, Acts::binX);
+    auto             pPlaneMaterial
+        = std::make_shared<const Acts::ProtoSurfaceMaterial>(pPlaneUtility);
+
     //-------------------------------------------------------------------------------------
     // Beam Pipe
     //-------------------------------------------------------------------------------------
+    // BeamPipe material
+    std::shared_ptr<const Acts::ISurfaceMaterial> beamPipeMaterial
+        = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+            Acts::MaterialProperties(352.8, 407., 9.012, 4., 1.848e-3, 0.8));
+    if (protoMaterial) {
+      beamPipeMaterial = pCylinderMaterial;
+    }
+
     // configure the beam pipe layer builder
     Acts::PassiveLayerBuilder::Config bplConfig;
     bplConfig.layerIdentification     = "BeamPipe";
     bplConfig.centralLayerRadii       = std::vector<double>(1, 19.);
     bplConfig.centralLayerHalflengthZ = std::vector<double>(1, 3000.);
     bplConfig.centralLayerThickness   = std::vector<double>(1, 0.8);
-    bplConfig.centralLayerMaterial
-        = {std::make_shared<Acts::HomogeneousSurfaceMaterial>(
-            Acts::MaterialProperties(352.8, 407., 9.012, 4., 1.848e-3, 0.8))};
+    bplConfig.centralLayerMaterial    = {beamPipeMaterial};
     auto beamPipeBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
         bplConfig, Acts::getDefaultLogger("BeamPipeLayerBuilder", layerLLevel));
     // create the volume for the beam pipe
@@ -184,13 +214,44 @@ namespace Generic {
     // some prep work
     // envelope for layers
     std::pair<double, double> pcEnvelope(2., 2.);
-    // Module material - X0, L0, A, Z, Rho
-    Acts::Material pcMaterial(95.7, 465.2, 28.03, 14., 2.32e-3);
+
+    double pCentralModuleT = 0.15;
+    double pEndcapModuleT  = 0.15;
+
+    // Module material properties - X0, L0, A, Z, Rho
+    Acts::Material           pcMaterial(95.7, 465.2, 28.03, 14., 2.32e-3);
+    Acts::MaterialProperties pcModuleMaterial(
+        95.7, 465.2, 28.03, 14., 2.32e-3, pCentralModuleT);
+
+    Acts::MaterialProperties peModuleMaterial(
+        95.7, 465.2, 28.03, 14., 2.32e-3, pEndcapModuleT);
+
     // Layer material properties - thickness, X0, L0, A, Z, Rho
     Acts::MaterialProperties pcmbProperties(
         95.7, 465.2, 28.03, 14., 2.32e-3, 1.5 * Acts::units::_mm);
     Acts::MaterialProperties pcmecProperties(
         95.7, 465.2, 28.03, 14., 2.32e-3, 1.5 * Acts::units::_mm);
+
+    // Module, central and disc material
+    std::shared_ptr<const Acts::ISurfaceMaterial> pCentralMaterial
+        = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+            pcmbProperties);
+    std::shared_ptr<const Acts::ISurfaceMaterial> pEndcapMaterial
+        = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+            pcmecProperties);
+    std::shared_ptr<const Acts::ISurfaceMaterial> pCentralModuleMaterial
+        = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+            pcModuleMaterial);
+    std::shared_ptr<const Acts::ISurfaceMaterial> pEndcapModuleMaterial
+        = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+            peModuleMaterial);
+    if (protoMaterial) {
+      pCentralMaterial       = pCylinderMaterial;
+      pCentralModuleMaterial = pPlaneMaterial;
+      pEndcapMaterial        = pDiscMaterial;
+      pEndcapModuleMaterial  = pPlaneMaterial;
+    }
+
     // configure the pixel proto layer builder
     typename ProtoLayerCreator::Config pplConfig;
     // standard, an approach envelope
@@ -204,12 +265,15 @@ namespace Generic {
         = {pcEnvelope, pcEnvelope, pcEnvelope, pcEnvelope};
     pplConfig.centralModuleBinningSchema
         = {{16, 14}, {32, 14}, {52, 14}, {78, 14}};
-    pplConfig.centralModuleTiltPhi   = {0.14, 0.14, 0.14, 0.14};
-    pplConfig.centralModuleHalfX     = {8.4, 8.4, 8.4, 8.4};
-    pplConfig.centralModuleHalfY     = {36., 36., 36., 36.};
-    pplConfig.centralModuleThickness = {0.15, 0.15, 0.15, 0.15};
-    pplConfig.centralModuleMaterial
-        = {pcMaterial, pcMaterial, pcMaterial, pcMaterial};
+    pplConfig.centralModuleTiltPhi = {0.14, 0.14, 0.14, 0.14};
+    pplConfig.centralModuleHalfX   = {8.4, 8.4, 8.4, 8.4};
+    pplConfig.centralModuleHalfY   = {36., 36., 36., 36.};
+    pplConfig.centralModuleThickness
+        = {pCentralModuleT, pCentralModuleT, pCentralModuleT, pCentralModuleT};
+    pplConfig.centralModuleMaterial = {pCentralModuleMaterial,
+                                       pCentralModuleMaterial,
+                                       pCentralModuleMaterial,
+                                       pCentralModuleMaterial};
     // pitch definitions
     pplConfig.centralModuleReadoutBinsX = {336, 336, 336, 336};
     pplConfig.centralModuleReadoutBinsY = {1280, 1280, 1280, 1280};
@@ -252,15 +316,17 @@ namespace Generic {
                                       1. * Acts::units::_mm,
                                       1. * Acts::units::_mm,
                                       1. * Acts::units::_mm};
-    std::vector<double>         perHX = {8.4, 8.4};    // half length x
-    std::vector<double>         perHY = {36., 36.};    // half length y
-    std::vector<size_t>         perBP = {40, 68};      // bins in phi
-    std::vector<double>         perT  = {0.15, 0.15};  // module thickness
-    std::vector<size_t>         perBX = {336, 336};    // bins in x
-    std::vector<size_t>         perBY = {1280, 1280};  // bins in y
-    std::vector<int>            perRS = {-1, -1};      // readout side
-    std::vector<double>         perLA = {0., 0.};      // lorentz angle
-    std::vector<Acts::Material> perM  = {pcMaterial, pcMaterial};  // material
+    std::vector<double> perHX = {8.4, 8.4};  // half length x
+    std::vector<double> perHY = {36., 36.};  // half length y
+    std::vector<size_t> perBP = {40, 68};    // bins in phi
+    std::vector<double> perT
+        = {pEndcapModuleT, pEndcapModuleT};    // module thickness
+    std::vector<size_t> perBX = {336, 336};    // bins in x
+    std::vector<size_t> perBY = {1280, 1280};  // bins in y
+    std::vector<int>    perRS = {-1, -1};      // readout side
+    std::vector<double> perLA = {0., 0.};      // lorentz angle
+    std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>> perM
+        = {pEndcapModuleMaterial, pEndcapModuleMaterial};  // material
 
     pplConfig.posnegModuleMinHalfX = std::vector<std::vector<double>>(7, perHX);
     pplConfig.posnegModuleMaxHalfX = {};
@@ -274,8 +340,9 @@ namespace Generic {
     pplConfig.posnegModuleReadoutSide = std::vector<std::vector<int>>(7, perRS);
     pplConfig.posnegModuleLorentzAngle
         = std::vector<std::vector<double>>(7, perLA);
-    pplConfig.posnegModuleMaterial
-        = std::vector<std::vector<Acts::Material>>(7, perM);
+    pplConfig.posnegModuleMaterial = std::
+        vector<std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>>(
+            7, perM);
 
     // no frontside/backside
     pplConfig.posnegModuleFrontsideStereo = {};
@@ -310,19 +377,19 @@ namespace Generic {
     plbConfig.centralProtoLayers
         = pplCreator.centralProtoLayers(gctx, detectorStore);
     plbConfig.centralLayerMaterialConcentration = {1, 1, 1, 1};
-    plbConfig.centralLayerMaterialProperties
-        = {pcmbProperties, pcmbProperties, pcmbProperties, pcmbProperties};
+    plbConfig.centralLayerMaterial              = {
+        pCentralMaterial, pCentralMaterial, pCentralMaterial, pCentralMaterial};
     if (level > 0) {
       // material concentration is always behind the layer in the pixels
       plbConfig.posnegLayerMaterialConcentration = std::vector<int>(7, 0);
       // layer structure surface has pixel material properties
-      plbConfig.posnegLayerMaterialProperties = {pcmecProperties,
-                                                 pcmecProperties,
-                                                 pcmecProperties,
-                                                 pcmecProperties,
-                                                 pcmecProperties,
-                                                 pcmecProperties,
-                                                 pcmecProperties};
+      plbConfig.posnegLayerMaterial = {pEndcapMaterial,
+                                       pEndcapMaterial,
+                                       pEndcapMaterial,
+                                       pEndcapMaterial,
+                                       pEndcapMaterial,
+                                       pEndcapMaterial,
+                                       pEndcapMaterial};
       // negative proto layers
       plbConfig.negativeProtoLayers
           = pplCreator.negativeProtoLayers(gctx, detectorStore);
@@ -353,14 +420,21 @@ namespace Generic {
       //-------------------------------------------------------------------------------------
       // Pixel Support Tybe (PST)
       //-------------------------------------------------------------------------------------
+      // Material
+      std::shared_ptr<const Acts::ISurfaceMaterial> pstMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              Acts::MaterialProperties(352.8, 407., 9.012, 4., 1.848e-3, 1.8));
+      if (protoMaterial) {
+        pstMaterial = pCylinderMaterial;
+      }
+
+      // Configuration
       Acts::PassiveLayerBuilder::Config pstConfig;
       pstConfig.layerIdentification     = "PST";
       pstConfig.centralLayerRadii       = std::vector<double>(1, 200.);
       pstConfig.centralLayerHalflengthZ = std::vector<double>(1, 2800.);
       pstConfig.centralLayerThickness   = std::vector<double>(1, 1.8);
-      pstConfig.centralLayerMaterial
-          = {std::make_shared<Acts::HomogeneousSurfaceMaterial>(
-              Acts::MaterialProperties(352.8, 407., 9.012, 4., 1.848e-3, 1.8))};
+      pstConfig.centralLayerMaterial    = {pstMaterial};
       auto pstBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
           pstConfig, Acts::getDefaultLogger("PSTBuilder", layerLLevel));
       // create the volume for the beam pipe
@@ -386,16 +460,46 @@ namespace Generic {
       // fill necessary vectors for configuration
       //-------------------------------------------------------------------------------------
       // some prep work
+
+      double ssCentralModuleT = 0.25;
+      double ssEndcapModuleT  = 0.25;
       // envelope double
       std::pair<double, double> ssEnvelope(2., 2.);
+
+      // Module material properties - X0, L0, A, Z, Rho
+      Acts::Material           sscMaterial(95.7, 465.2, 28.03, 14., 2.32e-3);
+      Acts::MaterialProperties sscModuleMaterial(
+          95.7, 465.2, 28.03, 14., 2.32e-3, ssCentralModuleT);
+
+      Acts::MaterialProperties sseModuleMaterial(
+          95.7, 465.2, 28.03, 14., 2.32e-3, ssEndcapModuleT);
+
       // Layer material properties - thickness, X0, L0, A, Z, Rho
       Acts::MaterialProperties ssbmProperties(
           95.7, 465.2, 28.03, 14., 2.32e-3, 2. * Acts::units::_mm);
       Acts::MaterialProperties ssecmProperties(
           95.7, 465.2, 28.03, 14., 2.32e-3, 2.5 * Acts::units::_mm);
 
-      // Module material - X0, L0, A, Z, Rho
-      Acts::Material ssMaterial(95.7, 465.2, 28.03, 14., 2.32e-3);
+      // Module, central and disc material
+      std::shared_ptr<const Acts::ISurfaceMaterial> ssCentralMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              ssbmProperties);
+      std::shared_ptr<const Acts::ISurfaceMaterial> ssEndcapMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              ssecmProperties);
+      std::shared_ptr<const Acts::ISurfaceMaterial> ssCentralModuleMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              sscModuleMaterial);
+      std::shared_ptr<const Acts::ISurfaceMaterial> ssEndcapModuleMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              sseModuleMaterial);
+      if (protoMaterial) {
+        ssCentralMaterial       = pCylinderMaterial;
+        ssCentralModuleMaterial = pPlaneMaterial;
+        ssEndcapMaterial        = pDiscMaterial;
+        ssEndcapModuleMaterial  = pPlaneMaterial;
+      }
+
       // ----------------------------------------------------------------------------
       // Configure the short strip proto layer builder
       typename ProtoLayerCreator::Config ssplConfig;
@@ -410,7 +514,10 @@ namespace Generic {
       ssplConfig.centralModuleTiltPhi   = {-0.15, -0.15, -0.15, -0.15};
       ssplConfig.centralModuleHalfX     = {24., 24., 24., 24.};
       ssplConfig.centralModuleHalfY     = {54., 54., 54., 54.};
-      ssplConfig.centralModuleThickness = {0.25, 0.25, 0.25, 0.25};
+      ssplConfig.centralModuleThickness = {ssCentralModuleT,
+                                           ssCentralModuleT,
+                                           ssCentralModuleT,
+                                           ssCentralModuleT};
 
       ssplConfig.centralModuleReadoutBinsX
           = {600, 600, 600, 600};  // 80 um pitch
@@ -419,8 +526,10 @@ namespace Generic {
       ssplConfig.centralModuleReadoutSide  = {1, 1, 1, 1};
       ssplConfig.centralModuleLorentzAngle = {0.12, 0.12, 0.12, 0.12};
 
-      ssplConfig.centralModuleMaterial
-          = {ssMaterial, ssMaterial, ssMaterial, ssMaterial};
+      ssplConfig.centralModuleMaterial = {ssCentralModuleMaterial,
+                                          ssCentralModuleMaterial,
+                                          ssCentralModuleMaterial,
+                                          ssCentralModuleMaterial};
       ssplConfig.centralModuleFrontsideStereo = {};
       ssplConfig.centralModuleBacksideStereo  = {};
       ssplConfig.centralModuleBacksideGap     = {};
@@ -449,10 +558,13 @@ namespace Generic {
       std::vector<int>    mrReadoutSide  = {1, 1, 1};
       std::vector<double> mrLorentzAngle = {0., 0., 0.};
 
-      std::vector<size_t>         mPhiBins   = {54, 56, 60};
-      std::vector<double>         mThickness = {0.25, 0.25, 0.25};
-      std::vector<Acts::Material> mMaterial
-          = {ssMaterial, ssMaterial, ssMaterial};
+      std::vector<size_t> mPhiBins = {54, 56, 60};
+      std::vector<double> mThickness
+          = {ssEndcapModuleT, ssEndcapModuleT, ssEndcapModuleT};
+      std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>> mMaterial
+          = {ssEndcapModuleMaterial,
+             ssEndcapModuleMaterial,
+             ssEndcapModuleMaterial};
 
       ssplConfig.posnegLayerBinMultipliers = {1, 2};
 
@@ -481,8 +593,9 @@ namespace Generic {
       ssplConfig.posnegModuleLorentzAngle
           = std::vector<std::vector<double>>(nposnegs, mrLorentzAngle);
 
-      ssplConfig.posnegModuleMaterial
-          = std::vector<std::vector<Acts::Material>>(nposnegs, mMaterial);
+      ssplConfig.posnegModuleMaterial = std::
+          vector<std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>>(
+              nposnegs, mMaterial);
 
       ssplConfig.posnegModuleFrontsideStereo = {};
       ssplConfig.posnegModuleBacksideStereo  = {};
@@ -517,8 +630,10 @@ namespace Generic {
       sslbConfig.centralProtoLayers
           = ssplCreator.centralProtoLayers(gctx, detectorStore);
       sslbConfig.centralLayerMaterialConcentration = {-1, -1, -1, -1};
-      sslbConfig.centralLayerMaterialProperties
-          = {ssbmProperties, ssbmProperties, ssbmProperties, ssbmProperties};
+      sslbConfig.centralLayerMaterial              = {ssCentralMaterial,
+                                         ssCentralMaterial,
+                                         ssCentralMaterial,
+                                         ssCentralMaterial};
 
       if (level > 2) {
         sslbConfig.negativeProtoLayers
@@ -528,8 +643,9 @@ namespace Generic {
 
         sslbConfig.posnegLayerMaterialConcentration
             = std::vector<int>(nposnegs, 0);
-        sslbConfig.posnegLayerMaterialProperties
-            = std::vector<Acts::MaterialProperties>(nposnegs, ssecmProperties);
+        sslbConfig.posnegLayerMaterial
+            = std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>(
+                nposnegs, ssEndcapMaterial);
       }
 
       // define the builder
@@ -558,16 +674,47 @@ namespace Generic {
       //-------------------------------------------------------------------------------------
       // fill necessary vectors for configuration
       //-------------------------------------------------------------------------------------
+
       // some prep work
       // envelope double
       std::pair<double, double> lsEnvelope(2., 2.);
+
+      double lsCentralModuleT = 0.35;
+      double lsEndcapModuleT  = 0.35;
+
+      // Module material properties - X0, L0, A, Z, Rho
+      Acts::Material           lsMaterial(95.7, 465.2, 28.03, 14., 2.32e-3);
+      Acts::MaterialProperties lscModuleMaterial(
+          95.7, 465.2, 28.03, 14., 2.32e-3, lsCentralModuleT);
+
+      Acts::MaterialProperties lseModuleMaterial(
+          95.7, 465.2, 28.03, 14., 2.32e-3, lsEndcapModuleT);
+
       // Layer material properties - thickness, X0, L0, A, Z, Rho - barrel
       Acts::MaterialProperties lsbmProperties(
           95.7, 465.2, 28.03, 14., 2.32e-3, 2.5 * Acts::units::_mm);
       Acts::MaterialProperties lsecmProperties(
           95.7, 465.2, 28.03, 14., 2.32e-3, 3.5 * Acts::units::_mm);
-      // Module material - X0, L0, A, Z, Rho
-      Acts::Material lsMaterial(95.7, 465.2, 28.03, 14., 2.32e-3);
+
+      // Module, central and disc material
+      std::shared_ptr<const Acts::ISurfaceMaterial> lsCentralMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              lsbmProperties);
+      std::shared_ptr<const Acts::ISurfaceMaterial> lsEndcapMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              lsecmProperties);
+      std::shared_ptr<const Acts::ISurfaceMaterial> lsCentralModuleMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              lscModuleMaterial);
+      std::shared_ptr<const Acts::ISurfaceMaterial> lsEndcapModuleMaterial
+          = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+              lseModuleMaterial);
+      if (protoMaterial) {
+        lsCentralMaterial       = pCylinderMaterial;
+        lsCentralModuleMaterial = pPlaneMaterial;
+        lsEndcapMaterial        = pDiscMaterial;
+        lsEndcapModuleMaterial  = pPlaneMaterial;
+      }
 
       // The proto layer creator
       typename ProtoLayerCreator::Config lsplConfig;
@@ -581,8 +728,9 @@ namespace Generic {
       lsplConfig.centralModuleTiltPhi       = {-0.15, -0.15};
       lsplConfig.centralModuleHalfX         = {24., 24.};
       lsplConfig.centralModuleHalfY         = {54., 54.};
-      lsplConfig.centralModuleThickness     = {0.35, 0.35};
-      lsplConfig.centralModuleMaterial      = {lsMaterial, lsMaterial};
+      lsplConfig.centralModuleThickness = {lsCentralModuleT, lsCentralModuleT};
+      lsplConfig.centralModuleMaterial
+          = {lsCentralModuleMaterial, lsCentralModuleMaterial};
 
       lsplConfig.centralModuleReadoutBinsX = {400, 400};  // 120 um pitch
       lsplConfig.centralModuleReadoutBinsY = {10, 10};    // 10 strips = 10.8 mm
@@ -611,8 +759,8 @@ namespace Generic {
       mrMaxHx    = {64.2, 72.};
       mrHy       = {78., 78.};
       mPhiBins   = {48, 50};
-      mThickness = {0.35, 0.35};
-      mMaterial  = {lsMaterial, lsMaterial};
+      mThickness = {lsEndcapModuleT, lsEndcapModuleT};
+      mMaterial  = {lsEndcapModuleMaterial, lsEndcapModuleMaterial};
 
       mrReadoutBinsX = {1070, 1200};  // 120 um pitch
       mrReadoutBinsY = {15, 15};      // 15 strips - 10.2 mm
@@ -646,8 +794,9 @@ namespace Generic {
       lsplConfig.posnegModuleLorentzAngle
           = std::vector<std::vector<double>>(nposnegs, mrLorentzAngle);
 
-      lsplConfig.posnegModuleMaterial
-          = std::vector<std::vector<Acts::Material>>(nposnegs, mMaterial);
+      lsplConfig.posnegModuleMaterial = std::
+          vector<std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>>(
+              nposnegs, mMaterial);
       lsplConfig.posnegModuleFrontsideStereo = {};
       lsplConfig.posnegModuleBacksideStereo  = {};
       lsplConfig.posnegModuleBacksideGap     = {};
@@ -678,16 +827,16 @@ namespace Generic {
       lslbConfig.layerCreator                      = layerCreator;
       lslbConfig.layerIdentification               = "LStrip";
       lslbConfig.centralLayerMaterialConcentration = {-1, -1};
-      lslbConfig.centralLayerMaterialProperties
-          = {lsbmProperties, lsbmProperties};
+      lslbConfig.centralLayerMaterial = {lsCentralMaterial, lsCentralMaterial};
       lslbConfig.centralProtoLayers
           = lsplCreator.centralProtoLayers(gctx, detectorStore);
 
       if (level > 2) {
         lslbConfig.posnegLayerMaterialConcentration
             = std::vector<int>(nposnegs, 0);
-        lslbConfig.posnegLayerMaterialProperties
-            = std::vector<Acts::MaterialProperties>(nposnegs, lsecmProperties);
+        lslbConfig.posnegLayerMaterial
+            = std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>(
+                nposnegs, lsEndcapMaterial);
         lslbConfig.negativeProtoLayers
             = lsplCreator.negativeProtoLayers(gctx, detectorStore);
         lslbConfig.positiveProtoLayers
@@ -721,10 +870,11 @@ namespace Generic {
     for (auto& vb : volumeBuilders) {
       tgConfig.trackingVolumeBuilders.push_back(
           [=](const auto& context, const auto& inner, const auto&) {
-            return vb->trackingVolume(gctx, inner);
+            return vb->trackingVolume(context, inner);
           });
     }
     tgConfig.trackingVolumeHelper = cylinderVolumeHelper;
+    tgConfig.materialDecorator    = matDecorator;
 
     auto cylinderGeometryBuilder
         = std::make_shared<const Acts::TrackingGeometryBuilder>(
diff --git a/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetector.hpp b/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetector.hpp
index 1bbcbce80b85c9b15d419c54001262f81d8ff83b..2649435be0c5c004dac5681a6bd8566ae8347caa 100644
--- a/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetector.hpp
+++ b/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetector.hpp
@@ -47,12 +47,15 @@ struct GenericGeometry
   /// optionally the geometry context decorator(s)
   ///
   /// @tparam variable_map_t Type of the variable map template for parameters
+  /// @tparam material_decorator_t Type of the material decorator
+  ///
   /// @param vm the parameter map object
+  /// @param mdecorator the actual material decorator
   ///
   /// @return a TrackingGeometry object, and optional context decorator(s)
-  template <typename variable_map_t>
+  template <typename variable_map_t, typename material_decorator_t>
   std::pair<TrackingGeometryPtr, ContextDecorators>
-  operator()(variable_map_t& vm)
+  operator()(variable_map_t& vm, material_decorator_t mdecorator)
   {
     // --------------------------------------------------------------------------------
     DetectorElement::ContextType nominalContext;
@@ -65,11 +68,17 @@ struct GenericGeometry
         = Acts::Logging::Level(vm["geo-layer-loglevel"].template as<size_t>());
     Acts::Logging::Level volumeLogLevel
         = Acts::Logging::Level(vm["geo-volume-loglevel"].template as<size_t>());
-    /// return the generic detector
+
+    bool buildProto
+        = (vm["mat-input-type"].template as<std::string>() == "proto");
+
+    /// Return the generic detector
     TrackingGeometryPtr gGeometry
         = FW::Generic::buildDetector<DetectorElement>(nominalContext,
                                                       detectorStore,
                                                       buildLevel,
+                                                      std::move(mdecorator),
+                                                      buildProto,
                                                       surfaceLogLevel,
                                                       layerLogLevel,
                                                       volumeLogLevel);
diff --git a/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetectorElement.hpp b/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetectorElement.hpp
index 55dcb77e8afb3b4de2fe8fc920e908bbac2d304e..3d816d6feafbe039da1433fc55436a0674a167f6 100644
--- a/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetectorElement.hpp
+++ b/Detectors/GenericDetector/include/ACTFW/GenericDetector/GenericDetectorElement.hpp
@@ -18,7 +18,7 @@ namespace Acts {
 class Surface;
 class PlanarBounds;
 class DiscBounds;
-class SurfaceMaterial;
+class ISurfaceMaterial;
 class DigitizationModule;
 }
 
@@ -50,7 +50,7 @@ namespace Generic {
         std::shared_ptr<const Acts::Transform3D>        transform,
         std::shared_ptr<const Acts::PlanarBounds>       pBounds,
         double                                          thickness,
-        std::shared_ptr<const Acts::SurfaceMaterial>    material = nullptr,
+        std::shared_ptr<const Acts::ISurfaceMaterial>   material = nullptr,
         std::shared_ptr<const Acts::DigitizationModule> digitzationModule
         = nullptr);
 
@@ -67,7 +67,7 @@ namespace Generic {
         std::shared_ptr<const Acts::Transform3D>        transform,
         std::shared_ptr<const Acts::DiscBounds>         dBounds,
         double                                          thickness,
-        std::shared_ptr<const Acts::SurfaceMaterial>    material = nullptr,
+        std::shared_ptr<const Acts::ISurfaceMaterial>   material = nullptr,
         std::shared_ptr<const Acts::DigitizationModule> digitzationModule
         = nullptr);
 
diff --git a/Detectors/GenericDetector/include/ACTFW/GenericDetector/LayerBuilderT.hpp b/Detectors/GenericDetector/include/ACTFW/GenericDetector/LayerBuilderT.hpp
index c7fd62a9fc5edb9d4021815bea8300210e9843b1..129e030bf7b53d345897ec893a6395724e9e9355 100644
--- a/Detectors/GenericDetector/include/ACTFW/GenericDetector/LayerBuilderT.hpp
+++ b/Detectors/GenericDetector/include/ACTFW/GenericDetector/LayerBuilderT.hpp
@@ -57,8 +57,9 @@ namespace Generic {
 
       /// the material concentration: -1 inner, 0 central, 1 outer
       std::vector<int> centralLayerMaterialConcentration;
-      /// the assigned material propertis @todo change to surface material
-      std::vector<Acts::MaterialProperties> centralLayerMaterialProperties;
+      /// The assigned surface material
+      std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>
+          centralLayerMaterial;
 
       /// The pre-produced proto layers for the negative part
       std::vector<ProtoLayerSurfaces> negativeProtoLayers;
@@ -66,18 +67,19 @@ namespace Generic {
       /// The pre-produced proto layers for the positive part
       std::vector<ProtoLayerSurfaces> positiveProtoLayers;
 
-      /// the material concentration: -1 inner, 0 central, 1 outer
+      /// The material concentration: -1 inner, 0 central, 1 outer
       std::vector<int> posnegLayerMaterialConcentration;
 
-      /// the material prooperties @todo change to surface material
-      std::vector<Acts::MaterialProperties> posnegLayerMaterialProperties;
+      /// The surface material
+      std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>
+          posnegLayerMaterial;
 
-      /// helper tools: layer creator
+      /// Helper tools: layer creator
       std::shared_ptr<const Acts::LayerCreator> layerCreator = nullptr;
-      /// helper tools: central passive layer builder
+      /// Helper tools: central passive layer builder
       std::shared_ptr<const Acts::ILayerBuilder> centralPassiveLayerBuilder
           = nullptr;
-      /// helper tools: p/n passive layer builder
+      /// Helper tools: p/n passive layer builder
       std::shared_ptr<const Acts::ILayerBuilder> posnegPassiveLayerBuilder
           = nullptr;
     };
@@ -142,16 +144,13 @@ namespace Generic {
           gctx, cpl.surfaces, cpl.bins0, cpl.bins1, cpl.protoLayer);
 
       // the layer is built let's see if it needs material
-      if (m_cfg.centralLayerMaterialProperties.size()) {
-        // get the material from configuration
-        Acts::MaterialProperties layerMaterialProperties
-            = m_cfg.centralLayerMaterialProperties.at(icl);
-        std::shared_ptr<const Acts::SurfaceMaterial> layerMaterialPtr(
-            new Acts::HomogeneousSurfaceMaterial(layerMaterialProperties));
+      if (m_cfg.centralLayerMaterial.size()) {
+        std::shared_ptr<const Acts::ISurfaceMaterial> layerMaterialPtr
+            = m_cfg.centralLayerMaterial.at(icl);
         // central material
         if (m_cfg.centralLayerMaterialConcentration.at(icl) == 0.) {
           // the layer surface is the material surface
-          cLayer->surfaceRepresentation().setAssociatedMaterial(
+          cLayer->surfaceRepresentation().assignSurfaceMaterial(
               layerMaterialPtr);
           ACTS_VERBOSE("- and material at central layer surface.");
         } else {
@@ -163,12 +162,12 @@ namespace Generic {
           if (m_cfg.centralLayerMaterialConcentration.at(icl) > 0) {
             auto mutableOuterSurface
                 = const_cast<Acts::Surface*>(approachSurfaces.at(1));
-            mutableOuterSurface->setAssociatedMaterial(layerMaterialPtr);
+            mutableOuterSurface->assignSurfaceMaterial(layerMaterialPtr);
             ACTS_VERBOSE("- and material at outer approach surface");
           } else {
             auto mutableInnerSurface
                 = const_cast<Acts::Surface*>(approachSurfaces.at(0));
-            mutableInnerSurface->setAssociatedMaterial(layerMaterialPtr);
+            mutableInnerSurface->assignSurfaceMaterial(layerMaterialPtr);
             ACTS_VERBOSE("- and material at inner approach surface");
           }
         }
@@ -228,15 +227,14 @@ namespace Generic {
           gctx, ple.surfaces, ple.bins0, ple.bins1, ple.protoLayer);
 
       // the layer is built let's see if it needs material
-      if (m_cfg.posnegLayerMaterialProperties.size()) {
-        std::shared_ptr<const Acts::SurfaceMaterial> layerMaterialPtr(
-            new Acts::HomogeneousSurfaceMaterial(
-                m_cfg.posnegLayerMaterialProperties[ipnl]));
+      if (m_cfg.posnegLayerMaterial.size()) {
+        std::shared_ptr<const Acts::ISurfaceMaterial> layerMaterialPtr
+            = m_cfg.posnegLayerMaterial[ipnl];
         // central material
         if (m_cfg.posnegLayerMaterialConcentration.at(ipnl) == 0.) {
           // assign the surface material - the layer surface is the material
           // surface
-          eLayer->surfaceRepresentation().setAssociatedMaterial(
+          eLayer->surfaceRepresentation().assignSurfaceMaterial(
               layerMaterialPtr);
           ACTS_VERBOSE("- and material at central layer surface.");
         } else {
@@ -249,13 +247,13 @@ namespace Generic {
             int  sf = side < 0 ? 0 : 1;
             auto mutableInnerSurface
                 = const_cast<Acts::Surface*>(approachSurfaces.at(sf));
-            mutableInnerSurface->setAssociatedMaterial(layerMaterialPtr);
+            mutableInnerSurface->assignSurfaceMaterial(layerMaterialPtr);
             ACTS_VERBOSE("- and material at outer approach surfaces.");
           } else {
             int  sf = side < 0 ? 1 : 0;
             auto mutableOuterSurface
                 = const_cast<Acts::Surface*>(approachSurfaces.at(sf));
-            mutableOuterSurface->setAssociatedMaterial(layerMaterialPtr);
+            mutableOuterSurface->assignSurfaceMaterial(layerMaterialPtr);
             ACTS_VERBOSE("- and material at inner approach surfaces.");
           }
         }
diff --git a/Detectors/GenericDetector/include/ACTFW/GenericDetector/ProtoLayerCreatorT.hpp b/Detectors/GenericDetector/include/ACTFW/GenericDetector/ProtoLayerCreatorT.hpp
index 1a0375f2d625314984361c6eced5891a6c9df68d..dc900895a3918ee45ea7c94da3e36da71c9010ed 100644
--- a/Detectors/GenericDetector/include/ACTFW/GenericDetector/ProtoLayerCreatorT.hpp
+++ b/Detectors/GenericDetector/include/ACTFW/GenericDetector/ProtoLayerCreatorT.hpp
@@ -14,9 +14,7 @@
 #include "Acts/Detector/DetectorElementBase.hpp"
 #include "Acts/Layers/ApproachDescriptor.hpp"
 #include "Acts/Layers/ProtoLayer.hpp"
-#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
-#include "Acts/Material/Material.hpp"
-#include "Acts/Material/MaterialProperties.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
 #include "Acts/Plugins/Digitization/CartesianSegmentation.hpp"
 #include "Acts/Plugins/Digitization/DigitizationModule.hpp"
 #include "Acts/Surfaces/PlanarBounds.hpp"
@@ -103,8 +101,9 @@ namespace Generic {
       std::vector<int> centralModuleReadoutSide;
       /// the central volume readout schema
       std::vector<double> centralModuleLorentzAngle;
-      /// the module material @todo change to surface material
-      std::vector<Acts::Material> centralModuleMaterial;
+      /// the module material
+      std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>
+          centralModuleMaterial;
       /// the module front side stereo (if exists)
       std::vector<double> centralModuleFrontsideStereo;
       /// the module back side stereo (if exists)
@@ -140,8 +139,9 @@ namespace Generic {
       std::vector<std::vector<int>> posnegModuleReadoutSide;
       /// the central volume readout schema
       std::vector<std::vector<double>> posnegModuleLorentzAngle;
-      /// the module material @todo change to surface material
-      std::vector<std::vector<Acts::Material>> posnegModuleMaterial;
+      /// the module material
+      std::vector<std::vector<std::shared_ptr<const Acts::ISurfaceMaterial>>>
+          posnegModuleMaterial;
       /// the module front side stereo (if exists)
       std::vector<std::vector<double>> posnegModuleFrontsideStereo;
       /// the module back side stereo (if exists)
@@ -282,23 +282,18 @@ namespace Generic {
           moduleDigitizationPtr
               = std::make_shared<const Acts::DigitizationModule>(
                   moduleSegmentation,
-                  m_cfg.centralModuleThickness.at(icl),
+                  0.5 * m_cfg.centralModuleThickness.at(icl),
                   m_cfg.centralModuleReadoutSide.at(icl),
                   m_cfg.centralModuleLorentzAngle.at(icl));
         }
 
         // prepartation :
         // create the Module material from input
-        std::shared_ptr<const Acts::SurfaceMaterial> moduleMaterialPtr
+        std::shared_ptr<const Acts::ISurfaceMaterial> moduleMaterialPtr
             = nullptr;
         if (m_cfg.centralModuleMaterial.size()) {
           // get the sensor material from configuration
-          Acts::Material moduleMaterial = m_cfg.centralModuleMaterial.at(icl);
-          Acts::MaterialProperties moduleMaterialProperties(moduleMaterial,
-                                                            moduleThickness);
-          // create a new surface material
-          moduleMaterialPtr = std::shared_ptr<const Acts::SurfaceMaterial>(
-              new Acts::HomogeneousSurfaceMaterial(moduleMaterialProperties));
+          moduleMaterialPtr = m_cfg.centralModuleMaterial.at(icl);
         }
 
         // confirm
@@ -524,20 +519,17 @@ namespace Generic {
             moduleDigitizationPtr
                 = std::make_shared<const Acts::DigitizationModule>(
                     moduleSegmentation,
-                    moduleThickness,
+                    0.5 * moduleThickness,
                     m_cfg.posnegModuleReadoutSide.at(ipnl).at(ipnR),
                     m_cfg.posnegModuleLorentzAngle.at(ipnl).at(ipnR));
           }
           // (3) module material
           // create the Module material from input
-          std::shared_ptr<const Acts::SurfaceMaterial> moduleMaterialPtr
+          std::shared_ptr<const Acts::ISurfaceMaterial> moduleMaterialPtr
               = nullptr;
           if (m_cfg.posnegModuleMaterial.size()) {
-            Acts::MaterialProperties moduleMaterialProperties(
-                m_cfg.posnegModuleMaterial.at(ipnl).at(ipnR), moduleThickness);
             // and create the shared pointer
-            moduleMaterialPtr = std::shared_ptr<const Acts::SurfaceMaterial>(
-                new Acts::HomogeneousSurfaceMaterial(moduleMaterialProperties));
+            moduleMaterialPtr = m_cfg.posnegModuleMaterial.at(ipnl).at(ipnR);
           }
 
           // low loop over the phi positions and build the stuff
@@ -572,7 +564,8 @@ namespace Generic {
                                                        moduleTransform,
                                                        moduleBounds,
                                                        moduleThickness,
-                                                       moduleMaterialPtr);
+                                                       moduleMaterialPtr,
+                                                       moduleDigitizationPtr);
             layerStore.push_back(module);
 
             // now deal with the potential backside
@@ -605,7 +598,8 @@ namespace Generic {
                                                          moduleTransform,
                                                          moduleBounds,
                                                          moduleThickness,
-                                                         moduleMaterialPtr);
+                                                         moduleMaterialPtr,
+                                                         moduleDigitizationPtr);
               // Put into the detector store
               layerStore.push_back(std::move(bsmodule));
               // register the backside of the binmembers
@@ -630,9 +624,9 @@ namespace Generic {
           layerBinsR *= m_cfg.posnegLayerBinMultipliers.first;
         }
         size_t layerBinsPhi = 0;
-        // take the maximum phi bins in that layer
+        // take the minimum phi bins in that layer
         for (unsigned int phiBins : m_cfg.posnegModulePhiBins.at(ipnl)) {
-          layerBinsPhi = phiBins > layerBinsPhi ? phiBins : layerBinsPhi;
+          layerBinsPhi = phiBins < layerBinsPhi ? phiBins : layerBinsPhi;
           layerBinsPhi *= m_cfg.posnegLayerBinMultipliers.second;
         }
         // create the layers with the surface arrays
diff --git a/Detectors/GenericDetector/src/GenericDetectorElement.cpp b/Detectors/GenericDetector/src/GenericDetectorElement.cpp
index 1648f57b628856f4a3ce585eb5c73ca50cab27d6..dd003ed4736eeafcce1b7783d93c28971cc3002a 100644
--- a/Detectors/GenericDetector/src/GenericDetectorElement.cpp
+++ b/Detectors/GenericDetector/src/GenericDetectorElement.cpp
@@ -17,7 +17,7 @@ FW::Generic::GenericDetectorElement::GenericDetectorElement(
     std::shared_ptr<const Acts::Transform3D>        transform,
     std::shared_ptr<const Acts::PlanarBounds>       pBounds,
     double                                          thickness,
-    std::shared_ptr<const Acts::SurfaceMaterial>    material,
+    std::shared_ptr<const Acts::ISurfaceMaterial>   material,
     std::shared_ptr<const Acts::DigitizationModule> digitizationModule)
   : Acts::IdentifiedDetectorElement()
   , m_elementIdentifier(std::move(identifier))
@@ -31,7 +31,7 @@ FW::Generic::GenericDetectorElement::GenericDetectorElement(
 {
   auto mutableSurface
       = std::const_pointer_cast<Acts::Surface>(m_elementSurface);
-  mutableSurface->setAssociatedMaterial(material);
+  mutableSurface->assignSurfaceMaterial(material);
 }
 
 FW::Generic::GenericDetectorElement::GenericDetectorElement(
@@ -39,7 +39,7 @@ FW::Generic::GenericDetectorElement::GenericDetectorElement(
     std::shared_ptr<const Acts::Transform3D>        transform,
     std::shared_ptr<const Acts::DiscBounds>         dBounds,
     double                                          thickness,
-    std::shared_ptr<const Acts::SurfaceMaterial>    material,
+    std::shared_ptr<const Acts::ISurfaceMaterial>   material,
     std::shared_ptr<const Acts::DigitizationModule> digitizationModule)
   : Acts::IdentifiedDetectorElement()
   , m_elementIdentifier(std::move(identifier))
@@ -53,5 +53,5 @@ FW::Generic::GenericDetectorElement::GenericDetectorElement(
 {
   auto mutableSurface
       = std::const_pointer_cast<Acts::Surface>(m_elementSurface);
-  mutableSurface->setAssociatedMaterial(material);
+  mutableSurface->assignSurfaceMaterial(material);
 }
diff --git a/Detectors/GeometryInterfaces/include/ACTFW/GeometryInterfaces/ITrackingGeometryService.hpp b/Detectors/GeometryInterfaces/include/ACTFW/GeometryInterfaces/ITrackingGeometryService.hpp
index ab6735c66a4e892a18135628209f9cf47a1ce9a3..73e4223a93e60ac5433dd74dbb132119f265b414 100644
--- a/Detectors/GeometryInterfaces/include/ACTFW/GeometryInterfaces/ITrackingGeometryService.hpp
+++ b/Detectors/GeometryInterfaces/include/ACTFW/GeometryInterfaces/ITrackingGeometryService.hpp
@@ -10,7 +10,7 @@
 // ITrackingGeometryService.hpp
 ///////////////////////////////////////////////////////////////////
 
-#pragma
+#pragma once
 
 #include <memory>
 #include "ACTFW/Framework/IService.hpp"
diff --git a/Detectors/TGeoDetector/include/ACTFW/TGeoDetector/TGeoDetector.hpp b/Detectors/TGeoDetector/include/ACTFW/TGeoDetector/TGeoDetector.hpp
index ac2e8394d296d9d382eb3e5005488c8b07fc6d0b..00a5102e8c7c60646bef1f2a785ab361d7594d75 100644
--- a/Detectors/TGeoDetector/include/ACTFW/TGeoDetector/TGeoDetector.hpp
+++ b/Detectors/TGeoDetector/include/ACTFW/TGeoDetector/TGeoDetector.hpp
@@ -42,12 +42,15 @@ struct TGeoGeometry
   /// optionally the geometry context decorator(s)
   ///
   /// @tparam variable_map_t Type of the variable map template for parameters
+  /// @tparam material_decorator_t Type of the material decorator
+  ///
   /// @param vm the parameter map object
+  /// @param mdecorator the actual material decorator
   ///
   /// @return a TrackingGeometry object, and optional context decorator(s)
-  template <typename variable_map_t>
+  template <typename variable_map_t, typename material_decorator_t>
   std::pair<TrackingGeometryPtr, ContextDecorators>
-  operator()(variable_map_t& vm)
+  operator()(variable_map_t& vm, material_decorator_t /*mdecorator*/)
   {
     Acts::GeometryContext tGeoContext;
     TrackingGeometryPtr   tgeoTrackingGeometry
diff --git a/Examples/BField/src/BFieldAccessExample.cpp b/Examples/BField/src/BFieldAccessExample.cpp
index aa9f1c42a62944a63e6b261a50b8c349b3c3ccc1..0fef5a1ec6d861688d5aff80734077c36c0ec66c 100644
--- a/Examples/BField/src/BFieldAccessExample.cpp
+++ b/Examples/BField/src/BFieldAccessExample.cpp
@@ -124,7 +124,7 @@ accessRandom(field_t&         bField,
             << " mismatches" << std::endl;
 }
 
-/// @brief Main executable
+/// @brief main executable
 ///
 /// @param argc The argument count
 /// @param argv The argument list
diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt
index 91179efea14f1e50a372e0163dcf9e088673b59f..8a2265ba7e287da791a7aead9a4b4a3c9c5923f4 100644
--- a/Examples/CMakeLists.txt
+++ b/Examples/CMakeLists.txt
@@ -6,7 +6,7 @@ add_subdirectory(EventGenerator)
 add_subdirectory_if(Fatras USE_PYTHIA8)
 add_subdirectory(Geometry)
 add_subdirectory(HelloWorld)
-#add_subdirectory_if(MaterialMapping USE_DD4HEP AND USE_GEANT4)
+add_subdirectory(MaterialMapping)
 add_subdirectory(Propagation)
 add_subdirectory(RandomNumbers)
 add_subdirectory(WhiteBoard)
diff --git a/Examples/Common/ACTFW/Geometry/CommonGeometry.hpp b/Examples/Common/ACTFW/Geometry/CommonGeometry.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad88a025a891cc4acb6f868c42793e61eaf60e49
--- /dev/null
+++ b/Examples/Common/ACTFW/Geometry/CommonGeometry.hpp
@@ -0,0 +1,66 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2019 Acts project team
+//
+// 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 <string>
+
+#include <Acts/Material/IMaterialDecorator.hpp>
+#include <Acts/Utilities/Logger.hpp>
+#include "ACTFW/Geometry/MaterialWiper.hpp"
+#include "ACTFW/Plugins/Json/JsonGeometryConverter.hpp"
+#include "ACTFW/Plugins/Json/JsonMaterialDecorator.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialDecorator.hpp"
+
+namespace FW {
+namespace Geometry {
+
+  /// @brief helper method to setup the geometry
+  ///
+  /// @tparam options_map_t Type of the options to be read
+  /// @tparam geometry_setupt_t Type of the callable geometry setup
+  ///
+  /// @param vm the parsed options map
+  /// @param geometrySetup the callable geometry setup
+  ///
+  /// @return a pair of TrackingGeometry and context decorators
+  template <typename options_map_t, typename geometry_setup_t>
+  auto
+  build(const options_map_t& vm, geometry_setup_t& geometrySetup)
+  {
+
+    // Material decoration
+    std::shared_ptr<const Acts::IMaterialDecorator> matDeco = nullptr;
+    auto matType = vm["mat-input-type"].template as<std::string>();
+    if (matType == "none") {
+      matDeco = std::make_shared<const Acts::MaterialWiper>();
+    } else if (matType == "file") {
+      // Retrieve the filename
+      auto fileName = vm["mat-input-file"].template as<std::string>();
+      // json or root based decorator
+      if (fileName.find(".json") != std::string::npos) {
+        // Set up the converter first
+        FW::Json::JsonGeometryConverter::Config jsonGeoConvConfig;
+        // Set up the json-based decorator
+        matDeco = std::make_shared<const FW::Json::JsonMaterialDecorator>(
+            jsonGeoConvConfig, fileName);
+      } else if (fileName.find(".root") != std::string::npos) {
+        // Set up the root-based decorator
+        FW::Root::RootMaterialDecorator::Config rootMatDecConfig;
+        rootMatDecConfig.fileName = fileName;
+        matDeco = std::make_shared<const FW::Root::RootMaterialDecorator>(
+            rootMatDecConfig);
+      }
+    }
+
+    /// Return the geometry and context decorators
+    return geometrySetup(vm, matDeco);
+  }
+
+}  // namespace
+}  // namespace
diff --git a/Examples/Common/ACTFW/Geometry/MaterialWiper.hpp b/Examples/Common/ACTFW/Geometry/MaterialWiper.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d8a7269536ce17ba334b3defc302970b79336af
--- /dev/null
+++ b/Examples/Common/ACTFW/Geometry/MaterialWiper.hpp
@@ -0,0 +1,48 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2019 Acts project team
+//
+// 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/.
+
+///////////////////////////////////////////////////////////////////
+// MaterialWiper.hpp, Acts project
+///////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "Acts/Detector/TrackingVolume.hpp"
+#include "Acts/Material/IMaterialDecorator.hpp"
+#include "Acts/Surfaces/Surface.hpp"
+
+// @note This file will go into the acts-core
+namespace Acts {
+
+/// @class MaterialWiper
+///
+/// This decorator sets the nulls-material
+///
+class MaterialWiper : public IMaterialDecorator
+{
+public:
+  /// Decorate a surface
+  ///
+  /// @param surface the non-cost surface that is decorated
+  void
+  decorate(Surface& surface) const final
+  {
+    surface.assignSurfaceMaterial(nullptr);
+  }
+
+  /// Decorate a TrackingVolume
+  ///
+  /// @param volume the non-cost volume that is decorated
+  virtual void
+  decorate(TrackingVolume& volume) const final
+  {
+    volume.assignVolumeMaterial(nullptr);
+  }
+};
+
+}  // namespace
\ No newline at end of file
diff --git a/Examples/Common/ACTFW/Options/CommonOptions.cpp b/Examples/Common/ACTFW/Options/CommonOptions.cpp
index 8ad2632beab5ef6f11742fb3affec71b0d9cd3fc..a7aaed2ad74aa84660b2e158d4dca8a197899c76 100644
--- a/Examples/Common/ACTFW/Options/CommonOptions.cpp
+++ b/Examples/Common/ACTFW/Options/CommonOptions.cpp
@@ -62,6 +62,40 @@ FW::Options::addGeometryOptions(
       "Sub detectors for the output writing");
 }
 
+void
+FW::Options::addMaterialOptions(
+    boost::program_options::options_description& opt)
+{
+  opt.add_options()(
+      "mat-input-type",
+      value<std::string>()->default_value("build"),
+      "The way material is loaded: 'none', 'build', 'proto', 'file'.")(
+      "mat-input-file",
+      value<std::string>()->default_value(""),
+      "Name of the material map input file, supported: '.json' or '.root'.")(
+      "mat-output-file",
+      value<std::string>()->default_value(""),
+      "Name of the material map output file (without extension).")(
+      "mat-output-sensitives",
+      value<bool>()->default_value(true),
+      "Write material information of sensitive surfaces.")(
+      "mat-output-approaches",
+      value<bool>()->default_value(true),
+      "Write material information of approach surfaces.")(
+      "mat-output-representing",
+      value<bool>()->default_value(true),
+      "Write material information of representing surfaces.")(
+      "mat-output-boundaries",
+      value<bool>()->default_value(true),
+      "Write material information of boundary surfaces.")(
+      "mat-output-volumes",
+      value<bool>()->default_value(true),
+      "Write material information of dense volumes.")(
+      "mat-output-data",
+      value<bool>()->default_value(true),
+      "Output the data field(s).");
+}
+
 void
 FW::Options::addOutputOptions(boost::program_options::options_description& opt)
 {
@@ -83,6 +117,28 @@ FW::Options::addOutputOptions(boost::program_options::options_description& opt)
       "Switch on to write '.json' ouput file(s).");
 }
 
+void
+FW::Options::addInputOptions(boost::program_options::options_description& opt)
+{
+  // Add specific options for this example
+  opt.add_options()("input-dir",
+                    value<std::string>()->default_value(""),
+                    "Input directory location.")(
+      "input-files",
+      value<read_strings>()->multitoken()->default_value({}),
+      "Input files, space separated.")("input-root",
+                                       value<bool>()->default_value(false),
+                                       "Switch on to read '.root' file(s).")(
+      "input-csv",
+      value<bool>()->default_value(false),
+      "Switch on to read '.csv' file(s).")("input-obj",
+                                           value<bool>()->default_value(false),
+                                           "Switch on to read '.obj' file(s).")(
+      "input-json",
+      value<bool>()->default_value(false),
+      "Switch on to read '.json' file(s).");
+}
+
 boost::program_options::variables_map
 FW::Options::parse(const boost::program_options::options_description& opt,
                    int                                                argc,
diff --git a/Examples/Common/ACTFW/Options/CommonOptions.hpp b/Examples/Common/ACTFW/Options/CommonOptions.hpp
index 4f5f2a3178b72903cf49555be166afafad07f660..1cdff661f2356358603f7db1d6d1b5d0356a5ec8 100644
--- a/Examples/Common/ACTFW/Options/CommonOptions.hpp
+++ b/Examples/Common/ACTFW/Options/CommonOptions.hpp
@@ -12,7 +12,6 @@
 
 #include <Acts/Utilities/Logger.hpp>
 #include <boost/program_options.hpp>
-
 #include "ACTFW/Framework/Sequencer.hpp"
 
 namespace FW {
@@ -32,6 +31,14 @@ namespace Options {
   void
   addGeometryOptions(boost::program_options::options_description& opt);
 
+  /// Add common material-related options.
+  void
+  addMaterialOptions(boost::program_options::options_description& opt);
+
+  /// Add common input-related options.
+  void
+  addInputOptions(boost::program_options::options_description& opt);
+
   /// Add common output-related options.
   void
   addOutputOptions(boost::program_options::options_description& opt);
diff --git a/Examples/Common/CMakeLists.txt b/Examples/Common/CMakeLists.txt
index ea361ef06e6d5665547044e9288c1b11a47746f7..2f5b8d33794bcdfa78d295817120674c11bafacb 100644
--- a/Examples/Common/CMakeLists.txt
+++ b/Examples/Common/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_library(ACTFWExamplesCommon STATIC ACTFW/Options/CommonOptions.cpp)
 target_include_directories(ACTFWExamplesCommon PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
 target_link_libraries(ACTFWExamplesCommon PUBLIC ActsCore ACTFramework)
+target_link_libraries(ACTFWExamplesCommon PUBLIC ACTFWObjPlugin ACTFWCsvPlugin ACTFWJsonPlugin ACTFWRootPlugin)
diff --git a/Examples/Fatras/src/detail/FatrasExampleBase.hpp b/Examples/Fatras/src/detail/FatrasExampleBase.hpp
index f5a69424474f44cfdb2f5140fdf4a86495afaf02..e0e0114987bf64622f8ccdc7bc09673e21e7c121 100644
--- a/Examples/Fatras/src/detail/FatrasExampleBase.hpp
+++ b/Examples/Fatras/src/detail/FatrasExampleBase.hpp
@@ -17,6 +17,7 @@
 #include "ACTFW/Fatras/FatrasOptions.hpp"
 #include "ACTFW/Framework/Sequencer.hpp"
 #include "ACTFW/Framework/WhiteBoard.hpp"
+#include "ACTFW/Geometry/CommonGeometry.hpp"
 #include "ACTFW/Options/CommonOptions.hpp"
 #include "ACTFW/Options/ParticleGunOptions.hpp"
 #include "ACTFW/Plugins/BField/BFieldOptions.hpp"
@@ -52,6 +53,7 @@ fatrasExample(int               argc,
   auto desc = FW::Options::makeDefaultOptions();
   FW::Options::addSequencerOptions(desc);
   FW::Options::addGeometryOptions(desc);
+  FW::Options::addMaterialOptions(desc);
   FW::Options::addParticleGunOptions(desc);
   FW::Options::addPythia8Options(desc);
   FW::Options::addRandomNumbersOptions(desc);
@@ -87,12 +89,11 @@ fatrasExample(int               argc,
   // Add it to the sequencer
   sequencer.addService(barcodeSvc);
 
-  // Create the geometry and the context decorators
-  auto geometry          = geometrySetup(vm);
+  // The geometry, material and decoration
+  auto geometry          = FW::Geometry::build(vm, geometrySetup);
   auto tGeometry         = geometry.first;
   auto contextDecorators = geometry.second;
-
-  // Add it to the sequencer
+  // Add the decorator to the sequencer
   for (auto cdr : contextDecorators) {
     sequencer.addContextDecorator(cdr);
   }
diff --git a/Examples/Fatras/src/detail/FatrasSimulationBase.hpp b/Examples/Fatras/src/detail/FatrasSimulationBase.hpp
index 73d2036f10bbf657c0c7c6db82e87e54c4b6cc90..90c65405d0bccacfa29c798111c36aad9375f7fd 100644
--- a/Examples/Fatras/src/detail/FatrasSimulationBase.hpp
+++ b/Examples/Fatras/src/detail/FatrasSimulationBase.hpp
@@ -72,7 +72,7 @@ struct SurfaceSelector
     if (selectSensitive && surface.associatedDetectorElement()) {
       return true;
     }
-    if (selectMaterial && surface.associatedMaterial()) {
+    if (selectMaterial && surface.surfaceMaterial()) {
       return true;
     }
     if (selectPassive) {
diff --git a/Examples/Geometry/CMakeLists.txt b/Examples/Geometry/CMakeLists.txt
index a52f44ddee5ec1e3f6050f7c5d59f9fe085c22c6..247d09c2a7b8e6753d6bfa7a4a3c4499c476db8b 100644
--- a/Examples/Geometry/CMakeLists.txt
+++ b/Examples/Geometry/CMakeLists.txt
@@ -1,55 +1,70 @@
-# generic detector
-add_executable(ACTFWGenericGeometryExample src/GenericGeometryExample)
-target_include_directories(ACTFWGenericGeometryExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWGenericGeometryExample PRIVATE ActsCore)
-target_link_libraries(ACTFWGenericGeometryExample PRIVATE ACTFramework ACTFWExamplesCommon)
-target_link_libraries(ACTFWGenericGeometryExample PRIVATE ACTFWObjPlugin ACTFWCsvPlugin ACTFWGenericDetector)
-target_link_libraries(ACTFWGenericGeometryExample PRIVATE ${Boost_LIBRARIES})
+set(_common_libraries
+  ActsCore
+  ACTFramework
+  ACTFWExamplesCommon
+  ACTFWObjPlugin
+  ACTFWCsvPlugin
+  ACTFWJsonPlugin
+  ACTFWRootPlugin
+  ${Boost_LIBRARIES})
 
-install(TARGETS ACTFWGenericGeometryExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+# Generic detector
+add_executable(ACTFWGenericGeometryExample src/GenericGeometryExample.cpp)
+target_include_directories(ACTFWGenericGeometryExample PRIVATE
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWGenericGeometryExample PRIVATE
+  ${_common_libraries}
+  ACTFWGenericDetector)
+install(
+  TARGETS ACTFWGenericGeometryExample
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-# alignable detector - with iov
-add_executable(ACTFWAlignedGeometryExample src/AlignedGeometryExample)
-target_include_directories(ACTFWAlignedGeometryExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWAlignedGeometryExample PRIVATE ActsCore)
-target_link_libraries(ACTFWAlignedGeometryExample PRIVATE ACTFramework ACTFWExamplesCommon)
-target_link_libraries(ACTFWAlignedGeometryExample PRIVATE ACTFWObjPlugin ACTFWCsvPlugin ACTFWGenericDetector ACTFWContextualDetector)
-target_link_libraries(ACTFWAlignedGeometryExample PRIVATE ${Boost_LIBRARIES})
+# Generic detector with IOV based alignment
+add_executable(ACTFWAlignedGeometryExample src/AlignedGeometryExample.cpp)
+target_include_directories(ACTFWAlignedGeometryExample PRIVATE
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWAlignedGeometryExample PRIVATE
+  ${_common_libraries}
+  ACTFWContextualDetector)
+install(
+  TARGETS ACTFWAlignedGeometryExample
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-install(TARGETS ACTFWAlignedGeometryExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-
-# alignable detector - with payload
-add_executable(ACTFWPayloadGeometryExample src/PayloadGeometryExample)
-target_include_directories(ACTFWPayloadGeometryExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWPayloadGeometryExample PRIVATE ActsCore)
-target_link_libraries(ACTFWPayloadGeometryExample PRIVATE ACTFramework ACTFWExamplesCommon)
-target_link_libraries(ACTFWPayloadGeometryExample PRIVATE ACTFWObjPlugin ACTFWCsvPlugin ACTFWGenericDetector ACTFWContextualDetector)
-target_link_libraries(ACTFWPayloadGeometryExample PRIVATE ${Boost_LIBRARIES})
-
-install(TARGETS ACTFWPayloadGeometryExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+# Generic detector with Payload based alignment
+add_executable(ACTFWPayloadGeometryExample src/PayloadGeometryExample.cpp)
+target_include_directories(ACTFWPayloadGeometryExample PRIVATE
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWPayloadGeometryExample PRIVATE
+  ${_common_libraries}
+  ACTFWContextualDetector)
+install(
+  TARGETS ACTFWPayloadGeometryExample
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # TGEO based detector
 if (USE_TGEO)
-  add_executable(ACTFWTGeoGeometryExample src/TGeoGeometryExample)
-  target_include_directories(ACTFWTGeoGeometryExample PUBLIC ${Boost_INCLUDE_DIRS})
-  target_link_libraries(ACTFWTGeoGeometryExample PRIVATE ActsCore)
-  target_link_libraries(ACTFWTGeoGeometryExample PRIVATE ACTFramework ACTFWExamplesCommon)
-  target_link_libraries(ACTFWTGeoGeometryExample PRIVATE ACTFWObjPlugin ACTFWCsvPlugin ACTFWTGeoDetector)
-  target_link_libraries(ACTFWTGeoGeometryExample PRIVATE ${Boost_LIBRARIES})
-
-  install(TARGETS ACTFWTGeoGeometryExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+  add_executable(ACTFWTGeoGeometryExample src/TGeoGeometryExample.cpp)
+  target_include_directories(ACTFWTGeoGeometryExample PRIVATE
+    ${Boost_INCLUDE_DIRS})
+  target_link_libraries(ACTFWTGeoGeometryExample PRIVATE
+    ${_common_libraries}
+    ACTFWTGeoDetector)
+  install(
+    TARGETS ACTFWTGeoGeometryExample
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
 
 # DD4hep detector
 if (USE_DD4HEP)
   add_executable(ACTFWDD4hepGeometryExample src/DD4hepGeometryExample.cpp)
-  target_include_directories(ACTFWDD4hepGeometryExample PRIVATE ${DD4hep_INCLUDE_DIRS})
-  target_include_directories(ACTFWDD4hepGeometryExample PRIVATE ${Boost_INCLUDE_DIRS})  
-  target_link_libraries(ACTFWDD4hepGeometryExample PRIVATE ActsCore)
-  target_link_libraries(ACTFWDD4hepGeometryExample PRIVATE ACTFramework ACTFWExamplesCommon)
-  target_link_libraries(ACTFWDD4hepGeometryExample PRIVATE ACTFWCsvPlugin ACTFWObjPlugin ACTFWDD4hepDetector)
-  target_link_libraries(ACTFWDD4hepGeometryExample PRIVATE ${DD4hep_LIBRARIES})
-  target_link_libraries(ACTFWDD4hepGeometryExample PRIVATE ${Boost_LIBRARIES})
-
-  install(TARGETS ACTFWDD4hepGeometryExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+  target_include_directories(ACTFWDD4hepGeometryExample PRIVATE
+    ${Boost_INCLUDE_DIRS}
+    ${DD4hep_INCLUDE_DIRS})
+  target_link_libraries(ACTFWDD4hepGeometryExample PRIVATE
+    ${_common_libraries}
+    ACTFWDD4hepDetector
+    ${DD4hep_LIBRARIES})
+  install(
+    TARGETS ACTFWDD4hepGeometryExample
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
diff --git a/Examples/Geometry/src/detail/GeometryExampleBase.hpp b/Examples/Geometry/src/detail/GeometryExampleBase.hpp
index cdf59c74b79c3854c655ff6d1471d5cb5952e5e5..bcef73b04ea414cf1aa5351d970ff7864a27417b 100644
--- a/Examples/Geometry/src/detail/GeometryExampleBase.hpp
+++ b/Examples/Geometry/src/detail/GeometryExampleBase.hpp
@@ -15,18 +15,28 @@
 #include "ACTFW/Framework/AlgorithmContext.hpp"
 #include "ACTFW/Framework/IContextDecorator.hpp"
 #include "ACTFW/Framework/WhiteBoard.hpp"
+#include "ACTFW/Geometry/CommonGeometry.hpp"
 #include "ACTFW/Options/CommonOptions.hpp"
 #include "ACTFW/Plugins/Csv/CsvSurfaceWriter.hpp"
 #include "ACTFW/Plugins/Csv/CsvTrackingGeometryWriter.hpp"
 #include "ACTFW/Plugins/Csv/CsvWriterOptions.hpp"
+#include "ACTFW/Plugins/Json/JsonMaterialWriter.hpp"
 #include "ACTFW/Plugins/Obj/ObjSurfaceWriter.hpp"
 #include "ACTFW/Plugins/Obj/ObjTrackingGeometryWriter.hpp"
 #include "ACTFW/Plugins/Obj/ObjWriterOptions.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialWriter.hpp"
 #include "ACTFW/Utilities/Options.hpp"
 #include "ACTFW/Utilities/Paths.hpp"
 #include "Acts/Detector/TrackingGeometry.hpp"
 #include "Acts/Utilities/GeometryContext.hpp"
 
+/// @brief templated method to process a geometry
+///
+/// @tparam options_setup_t callable options setup
+/// @tparam geometry_setup_t callable geonmetry setup
+///
+///
+
 template <typename options_setup_t, typename geometry_setup_t>
 int
 processGeometry(int               argc,
@@ -38,6 +48,7 @@ processGeometry(int               argc,
   auto desc = FW::Options::makeDefaultOptions();
   FW::Options::addSequencerOptions(desc);
   FW::Options::addGeometryOptions(desc);
+  FW::Options::addMaterialOptions(desc);
   FW::Options::addObjWriterOptions(desc);
   FW::Options::addOutputOptions(desc);
   // Add specific options for this geometry
@@ -49,10 +60,10 @@ processGeometry(int               argc,
 
   // Now read the standard options
   auto logLevel = FW::Options::readLogLevel(vm);
-  // TODO Check whether this truly needs to be event-based. If yes switch to
-  // Sequencer-based tool, otherwise remove.
-  auto nEvents           = FW::Options::readSequencerConfig(vm).events;
-  auto geometry          = geometrySetup(vm);
+  auto nEvents  = FW::Options::readSequencerConfig(vm).events;
+
+  // The geometry, material and decoration
+  auto geometry          = FW::Geometry::build(vm, geometrySetup);
   auto tGeometry         = geometry.first;
   auto contextDecorators = geometry.second;
 
@@ -60,11 +71,11 @@ processGeometry(int               argc,
   read_strings subDetectors = vm["geo-subdetectors"].as<read_strings>();
 
   auto surfaceLogLevel
-      = Acts::Logging::Level(vm["geo-surface-loglevel"].template as<size_t>());
+      = Acts::Logging::Level(vm["geo-surface-loglevel"].as<size_t>());
   auto layerLogLevel
-      = Acts::Logging::Level(vm["geo-layer-loglevel"].template as<size_t>());
+      = Acts::Logging::Level(vm["geo-layer-loglevel"].as<size_t>());
   auto volumeLogLevel
-      = Acts::Logging::Level(vm["geo-volume-loglevel"].template as<size_t>());
+      = Acts::Logging::Level(vm["geo-volume-loglevel"].as<size_t>());
 
   for (size_t ievt = 0; ievt < nEvents; ++ievt) {
 
@@ -168,6 +179,43 @@ processGeometry(int               argc,
       // Close the file
       csvStream->close();
     }
+
+    // Get the file name from the options
+    std::string materialFileName = vm["mat-output-file"].as<std::string>();
+
+    if (!materialFileName.empty() and vm["output-root"].template as<bool>()) {
+
+      // The writer of the indexed material
+      FW::Root::RootMaterialWriter::Config rmwConfig("MaterialWriter");
+      rmwConfig.fileName = materialFileName + ".root";
+      FW::Root::RootMaterialWriter rmwImpl(rmwConfig);
+      rmwImpl.write(*tGeometry);
+    }
+
+    if (!materialFileName.empty() and vm["output-json"].template as<bool>()) {
+      /// The name of the output file
+      std::string fileName = vm["mat-output-file"].template as<std::string>();
+      // the material writer
+      FW::Json::JsonGeometryConverter::Config jmConverterCfg(
+          "JsonGeometryConverter", Acts::Logging::INFO);
+      jmConverterCfg.processSensitives
+          = vm["mat-output-sensitives"].template as<bool>();
+      jmConverterCfg.processApproaches
+          = vm["mat-output-approaches"].template as<bool>();
+      jmConverterCfg.processRepresenting
+          = vm["mat-output-representing"].template as<bool>();
+      jmConverterCfg.processBoundaries
+          = vm["mat-output-boundaries"].template as<bool>();
+      jmConverterCfg.processVolumes
+          = vm["mat-output-volumes"].template as<bool>();
+      jmConverterCfg.writeData = vm["mat-output-data"].template as<bool>();
+
+      // The writer
+      FW::Json::JsonMaterialWriter jmwImpl(std::move(jmConverterCfg),
+                                           materialFileName + ".json");
+
+      jmwImpl.write(*tGeometry);
+    }
   }
 
   return 0;
diff --git a/Examples/MaterialMapping/CMakeLists.txt b/Examples/MaterialMapping/CMakeLists.txt
index 848cc2d1ef1f31c26e7962c3baf8fe94e7f38605..44520405bb867f91cc85ddcaf0794e14c4cae2cc 100644
--- a/Examples/MaterialMapping/CMakeLists.txt
+++ b/Examples/MaterialMapping/CMakeLists.txt
@@ -1,18 +1,45 @@
-include(${Geant4_USE_FILE})
+set(_common_libraries
+  ActsCore
+  ACTFramework
+  ACTFWExamplesCommon
+  ${Boost_LIBRARIES})
 
-file (GLOB_RECURSE src_files "src/*.cpp")
+set(_plugin_libraries
+  ACTFWRootPlugin
+  ACTFWJsonPlugin
+  ACTFWBFieldPlugin)
 
-add_executable(ACTFWGeantinoRecordingExample src/GeantinoRecordingExample.cpp)
-add_executable(ACTFWMaterialMappingExample src/MaterialMappingExample.cpp)
+add_executable(ACTFWGenericMaterialValidationExample src/GenericMaterialValidation.cpp)
+target_include_directories(ACTFWGenericMaterialValidationExample PRIVATE 
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWGenericMaterialValidationExample PRIVATE 
+  ${_common_libraries} ${_plugin_libraries})
+target_link_libraries(ACTFWGenericMaterialValidationExample PRIVATE 
+  ACTFWPropagation ACTFWGenericDetector)
+install(TARGETS ACTFWGenericMaterialValidationExample RUNTIME DESTINATION 
+  ${CMAKE_INSTALL_BINDIR})
 
-foreach(_example ACTFWGeantinoRecordingExample ACTFWMaterialMappingExample)
-  target_include_directories(${_example} PRIVATE ${DD4hep_INCLUDE_DIRS})
-  target_link_libraries(${_example} PRIVATE ACTFWDD4hepG4Plugin)
-  target_link_libraries(${_example} PRIVATE ACTFWExtrapolation)
-  target_link_libraries(${_example} PRIVATE ACTFWMaterialMapping)
-  target_link_libraries(${_example} PRIVATE ACTFWRootPlugin)
-  target_link_libraries(${_example} PRIVATE ${DD4hep_LIBRARIES})
-  target_link_libraries(${_example} PRIVATE ${Geant4_LIBRARIES})
-  target_link_libraries(${_example} PRIVATE ${Boost_LIBRARIES})
-  install(TARGETS ${_example} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-endforeach()
+add_executable(ACTFWGenericMaterialMappingExample src/GenericMaterialMapping.cpp)
+target_include_directories(ACTFWGenericMaterialMappingExample PRIVATE 
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE 
+  ${_common_libraries} ${_plugin_libraries})
+target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE 
+  ACTFWMaterialMapping ACTFWGenericDetector)
+install(TARGETS ACTFWGenericMaterialMappingExample RUNTIME DESTINATION 
+  ${CMAKE_INSTALL_BINDIR})
+
+
+if (USE_GEANT4 AND USE_DD4HEP)
+  include(${Geant4_USE_FILE})
+  
+  add_executable(ACTFWGeantinoRecordingExample src/GeantinoRecordingExample.cpp)
+  target_include_directories(ACTFWGeantinoRecordingExample PRIVATE 
+    ${Boost_INCLUDE_DIRS} ${DD4hep_INCLUDE_DIRS})
+  target_link_libraries(ACTFWGeantinoRecordingExample PRIVATE 
+   ACTFWExamplesCommon ACTFWMaterialMapping ACTFWDD4hepG4Plugin ACTFWRootPlugin)
+  target_link_libraries(ACTFWGeantinoRecordingExample PRIVATE 
+   ACTFWDD4hepDetector ${DD4hep_LIBRARIES} ${Geant4_LIBRARIES} ${Boost_LIBRARIES})
+   
+  install(TARGETS ACTFWGeantinoRecordingExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
diff --git a/Examples/MaterialMapping/src/GeantinoRecordingExample.cpp b/Examples/MaterialMapping/src/GeantinoRecordingExample.cpp
index c7d5a618b24e3d7049304a00fb9991dd6338beeb..ea33e52eab258414f8ed53bebcfd63fa1349736f 100644
--- a/Examples/MaterialMapping/src/GeantinoRecordingExample.cpp
+++ b/Examples/MaterialMapping/src/GeantinoRecordingExample.cpp
@@ -1,22 +1,23 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2018 Acts project team
 //
 // 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 <boost/program_options.hpp>
-#include "ACTFW/Common/CommonOptions.hpp"
+#include "ACTFW/DD4hepDetector/DD4hepDetectorOptions.hpp"
+#include "ACTFW/DD4hepDetector/DD4hepGeometryService.hpp"
 #include "ACTFW/Framework/Sequencer.hpp"
 #include "ACTFW/MaterialMapping/GeantinoRecording.hpp"
-#include "ACTFW/Plugins/DD4hep/DD4hepDetectorOptions.hpp"
-#include "ACTFW/Plugins/DD4hep/GeometryService.hpp"
+#include "ACTFW/Options/CommonOptions.hpp"
 #include "ACTFW/Plugins/DD4hepG4/DD4hepToG4Svc.hpp"
 #include "ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp"
 #include "ACTFW/Random/RandomNumbersSvc.hpp"
-#include "ACTFW/Writers/IWriterT.hpp"
+#include "ACTFW/Utilities/Paths.hpp"
 #include "Acts/Detector/TrackingGeometry.hpp"
+#include "Acts/Utilities/GeometryContext.hpp"
 
 namespace po = boost::program_options;
 
@@ -24,39 +25,36 @@ int
 main(int argc, char* argv[])
 {
   // Declare the supported program options.
-  po::options_description desc("Allowed options");
-  // add the standard options
-  FW::Options::addStandardOptions<po::options_description>(desc, 100, 2);
-  // add the detector options
-  FW::Options::addDD4hepOptions<po::options_description>(desc);
-  po::variables_map vm;
-  // Get all options from contain line and store it into the map
-  po::store(po::parse_command_line(argc, argv, desc), vm);
-  po::notify(vm);
-  // print help if requested
-  if (vm.count("help")) {
-    std::cout << desc << std::endl;
-    return 1;
+  // Setup and parse options
+  auto desc = FW::Options::makeDefaultOptions();
+  FW::Options::addSequencerOptions(desc);
+  FW::Options::addOutputOptions(desc);
+  FW::Options::addDD4hepOptions(desc);
+
+  // Parse the options
+  auto vm = FW::Options::parse(desc, argc, argv);
+  if (vm.empty()) {
+    return EXIT_FAILURE;
   }
-  // now read the standard options
-  auto standardOptions
-      = FW::Options::readStandardOptions<po::variables_map>(vm);
-  // @todo update - make program options in separate MR
-  auto   nEvents     = standardOptions.first;
+
+  FW::Sequencer g4sequencer(FW::Options::readSequencerConfig(vm));
+
   size_t nTracks     = 100;
   int    randomSeed1 = 536235167;
   int    randomSeed2 = 729237523;
 
+  Acts::GeometryContext geoContext;
+
   // DETECTOR:
   // --------------------------------------------------------------------------------
   // DD4Hep detector definition
   // read the detector config & dd4hep detector
   auto dd4HepDetectorConfig
       = FW::Options::readDD4hepConfig<po::variables_map>(vm);
-  auto geometrySvc
-      = std::make_shared<FW::DD4hep::GeometryService>(dd4HepDetectorConfig);
+  auto geometrySvc = std::make_shared<FW::DD4hep::DD4hepGeometryService>(
+      dd4HepDetectorConfig);
   std::shared_ptr<const Acts::TrackingGeometry> tGeometry
-      = geometrySvc->trackingGeometry();
+      = geometrySvc->trackingGeometry(geoContext);
 
   // DD4Hep to Geant4 conversion
   //
@@ -69,32 +67,36 @@ main(int argc, char* argv[])
   // Geant4 JOB:
   // --------------------------------------------------------------------------------
   // set up the writer for
-  FW::Root::RootMaterialTrackWriter::Config g4WriterConfig(
-      "MaterialTrackWriter", Acts::Logging::INFO);
-  g4WriterConfig.fileName = "GeantMaterialTracks.root";
-  g4WriterConfig.treeName = "GeantMaterialTracks";
-  auto g4TrackRecWriter
-      = std::make_shared<FW::Root::RootMaterialTrackWriter>(g4WriterConfig);
+
+  // ---------------------------------------------------------------------------------
 
   // set up the algorithm writing out the material map
   FW::GeantinoRecording::Config g4rConfig;
-  g4rConfig.materialTrackWriter = g4TrackRecWriter;
-  g4rConfig.geant4Service       = dd4hepToG4Svc;
-  g4rConfig.tracksPerEvent      = nTracks;
-  g4rConfig.seed1               = randomSeed1;
-  g4rConfig.seed2               = randomSeed2;
+  g4rConfig.geant4Service  = dd4hepToG4Svc;
+  g4rConfig.tracksPerEvent = nTracks;
+  g4rConfig.seed1          = randomSeed1;
+  g4rConfig.seed2          = randomSeed2;
   // create the geant4 algorithm
   auto g4rAlgorithm
       = std::make_shared<FW::GeantinoRecording>(g4rConfig, Acts::Logging::INFO);
 
-  // Geant4 job - these can be many Geant4 jobs, indeed
-  //
-  // create the config object for the sequencer
-  FW::Sequencer::Config g4SeqConfig;
-  // now create the sequencer
-  FW::Sequencer g4Sequencer(g4SeqConfig);
-  // the writer is a service as it needs initialize, finalize
-  g4Sequencer.addService(g4TrackRecWriter);
-  g4Sequencer.addAlgorithm(g4rAlgorithm);
-  return g4Sequencer.run(nEvents);
+  // Output directory
+  std::string outputDir     = vm["output-dir"].template as<std::string>();
+  std::string matCollection = g4rConfig.geantMaterialCollection;
+
+  if (vm["output-root"].template as<bool>()) {
+    // Write the propagation steps as ROOT TTree
+    FW::Root::RootMaterialTrackWriter::Config matTrackWriterRootConfig;
+    matTrackWriterRootConfig.collection = matCollection;
+    matTrackWriterRootConfig.filePath
+        = FW::joinPaths(outputDir, matCollection + ".root");
+    auto matTrackWriterRoot
+        = std::make_shared<FW::Root::RootMaterialTrackWriter>(
+            matTrackWriterRootConfig);
+    g4sequencer.addWriter(matTrackWriterRoot);
+  }
+
+  // Append the algorithm and run
+  g4sequencer.addAlgorithm(g4rAlgorithm);
+  g4sequencer.run();
 }
diff --git a/Examples/MaterialMapping/src/GenericMaterialMapping.cpp b/Examples/MaterialMapping/src/GenericMaterialMapping.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..815e645a76435e5f7096bf679c9620bd6b21ae7c
--- /dev/null
+++ b/Examples/MaterialMapping/src/GenericMaterialMapping.cpp
@@ -0,0 +1,24 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2018-2019 Acts project team
+//
+// 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 "ACTFW/GenericDetector/GenericDetector.hpp"
+#include "detail/MaterialMappingBase.hpp"
+
+/// @brief main executable
+///
+/// @param argc The argument count
+/// @param argv The argument list
+int
+main(int argc, char* argv[])
+{
+  // --------------------------------------------------------------------------------
+  GenericOptions  genericOptions;
+  GenericGeometry genericGeometry;
+  // now process it
+  return materialMappingExample(argc, argv, genericOptions, genericGeometry);
+}
\ No newline at end of file
diff --git a/Examples/MaterialMapping/src/GenericMaterialValidation.cpp b/Examples/MaterialMapping/src/GenericMaterialValidation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0cb0678da0f94a1b19971d18fe04995ebbd4935
--- /dev/null
+++ b/Examples/MaterialMapping/src/GenericMaterialValidation.cpp
@@ -0,0 +1,24 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2018 Acts project team
+//
+// 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 "ACTFW/GenericDetector/GenericDetector.hpp"
+#include "detail/MaterialValidationBase.hpp"
+
+/// @brief main executable
+///
+/// @param argc The argument count
+/// @param argv The argument list
+int
+main(int argc, char* argv[])
+{
+  // --------------------------------------------------------------------------------
+  GenericOptions  genericOptions;
+  GenericGeometry genericGeometry;
+  // now process it
+  return materialValidationExample(argc, argv, genericOptions, genericGeometry);
+}
\ No newline at end of file
diff --git a/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp b/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d2748d909765ea408b262c8179fe1991c39a915c
--- /dev/null
+++ b/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp
@@ -0,0 +1,176 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2018 Acts project team
+//
+// 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 <boost/program_options.hpp>
+#include <memory>
+#include "ACTFW/Framework/Sequencer.hpp"
+#include "ACTFW/Geometry/CommonGeometry.hpp"
+#include "ACTFW/MaterialMapping/MaterialMapping.hpp"
+#include "ACTFW/MaterialMapping/MaterialMappingOptions.hpp"
+#include "ACTFW/Options/CommonOptions.hpp"
+#include "ACTFW/Plugins/Json/JsonGeometryConverter.hpp"
+#include "ACTFW/Plugins/Json/JsonMaterialWriter.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialTrackReader.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialWriter.hpp"
+#include "ACTFW/Propagation/PropagationOptions.hpp"
+#include "ACTFW/Utilities/Paths.hpp"
+#include "Acts/Detector/TrackingGeometry.hpp"
+#include "Acts/Extrapolator/Navigator.hpp"
+#include "Acts/Plugins/MaterialMapping/SurfaceMaterialMapper.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/StraightLineStepper.hpp"
+#include "Acts/Utilities/GeometryContext.hpp"
+#include "Acts/Utilities/MagneticFieldContext.hpp"
+
+namespace po = boost::program_options;
+
+/// @brief The material validation example, it runs a propagation
+/// and then writes out the material information
+///
+/// @tparam option_setup_t Type of the option setter
+/// @tparam geometry_setup_t Type of the geometry setter
+///
+/// @param argc the number of argumetns of the call
+/// @param atgv the argument list
+/// @param optionsSetup is the access struct to the additional options
+/// @param geometrySetup is the access struct for the trackingGeometry
+///
+template <typename options_setup_t, typename geometry_setup_t>
+int
+materialMappingExample(int              argc,
+                       char*            argv[],
+                       options_setup_t  optionsSetup,
+                       geometry_setup_t geometrySetup)
+{
+
+  // Setup and parse options
+  auto desc = FW::Options::makeDefaultOptions();
+  FW::Options::addSequencerOptions(desc);
+  FW::Options::addGeometryOptions(desc);
+  FW::Options::addMaterialOptions(desc);
+  FW::Options::addMaterialMappingOptions(desc);
+  FW::Options::addPropagationOptions(desc);
+  FW::Options::addInputOptions(desc);
+  FW::Options::addOutputOptions(desc);
+
+  // Add specific options for this geometry
+  optionsSetup(desc);
+  auto vm = FW::Options::parse(desc, argc, argv);
+  if (vm.empty()) {
+    return EXIT_FAILURE;
+  }
+
+  FW::Sequencer sequencer(FW::Options::readSequencerConfig(vm));
+
+  // Get the log level
+  auto logLevel = FW::Options::readLogLevel(vm);
+
+  // The geometry, material and decoration
+  auto geometry  = FW::Geometry::build(vm, geometrySetup);
+  auto tGeometry = geometry.first;
+
+  /// Default contexts
+  Acts::GeometryContext      geoContext;
+  Acts::MagneticFieldContext mfContext;
+
+  // Get a Navigator
+  Acts::Navigator navigator(tGeometry);
+
+  // Straight line stepper
+  using SlStepper  = Acts::StraightLineStepper;
+  using Propagator = Acts::Propagator<SlStepper, Acts::Navigator>;
+  // Make stepper and propagator
+  SlStepper  stepper;
+  Propagator propagator(std::move(stepper), std::move(navigator));
+
+  auto matCollection = vm["mat-mapping-collection"].template as<std::string>();
+
+  // ---------------------------------------------------------------------------------
+  // Input directory & input file handling
+  std::string intputDir   = vm["input-dir"].template as<std::string>();
+  auto        intputFiles = vm["input-files"].template as<read_strings>();
+
+  if (vm["input-root"].template as<bool>()) {
+    // Read the material step information from a ROOT TTree
+    FW::Root::RootMaterialTrackReader::Config matTrackReaderRootConfig;
+    if (not matCollection.empty()) {
+      matTrackReaderRootConfig.collection = matCollection;
+    }
+    matTrackReaderRootConfig.fileList = intputFiles;
+    auto matTrackReaderRoot
+        = std::make_shared<FW::Root::RootMaterialTrackReader>(
+            matTrackReaderRootConfig);
+    sequencer.addReader(matTrackReaderRoot);
+  }
+
+  /// The material mapper
+  Acts::SurfaceMaterialMapper::Config smmConfig;
+  auto smm = std::make_shared<Acts::SurfaceMaterialMapper>(
+      smmConfig,
+      std::move(propagator),
+      Acts::getDefaultLogger("SurfaceMaterialMapper", logLevel));
+
+  /// The material mapping algorithm
+  FW::MaterialMapping::Config mmAlgConfig(geoContext, mfContext);
+  mmAlgConfig.materialMapper   = smm;
+  mmAlgConfig.trackingGeometry = tGeometry;
+
+  // Get the file name from the options
+  std::string materialFileName = vm["mat-output-file"].as<std::string>();
+
+  if (!materialFileName.empty() and vm["output-root"].template as<bool>()) {
+
+    // The writer of the indexed material
+    FW::Root::RootMaterialWriter::Config rmwConfig("MaterialWriter");
+    rmwConfig.fileName = materialFileName + ".root";
+    FW::Root::RootMaterialWriter rmwImpl(rmwConfig);
+    // Fullfill the IMaterialWriter interface
+    using RootWriter = FW::MaterialWriterT<FW::Root::RootMaterialWriter>;
+    mmAlgConfig.materialWriters.push_back(
+        std::make_shared<RootWriter>(std::move(rmwImpl)));
+  }
+
+  if (!materialFileName.empty() and vm["output-json"].template as<bool>()) {
+    /// The name of the output file
+    std::string fileName = vm["mat-output-file"].template as<std::string>();
+    // the material writer
+    FW::Json::JsonGeometryConverter::Config jmConverterCfg(
+        "JsonGeometryConverter", Acts::Logging::INFO);
+    jmConverterCfg.processSensitives
+        = vm["mat-output-sensitives"].template as<bool>();
+    jmConverterCfg.processApproaches
+        = vm["mat-output-approaches"].template as<bool>();
+    jmConverterCfg.processRepresenting
+        = vm["mat-output-representing"].template as<bool>();
+    jmConverterCfg.processBoundaries
+        = vm["mat-output-boundaries"].template as<bool>();
+    jmConverterCfg.processVolumes
+        = vm["mat-output-volumes"].template as<bool>();
+    jmConverterCfg.writeData = vm["mat-output-data"].template as<bool>();
+    // The writer
+    FW::Json::JsonMaterialWriter jmwImpl(jmConverterCfg,
+                                         materialFileName + ".json");
+    // Fullfill the IMaterialWriter interface
+    using JsonWriter = FW::MaterialWriterT<FW::Json::JsonMaterialWriter>;
+    mmAlgConfig.materialWriters.push_back(
+        std::make_shared<JsonWriter>(std::move(jmwImpl)));
+  }
+
+  // Create the material mapping
+  auto mmAlg = std::make_shared<FW::MaterialMapping>(mmAlgConfig);
+
+  // Append the Algorithm
+  sequencer.addAlgorithm(mmAlg);
+
+  // Initiate the run
+  sequencer.run();
+  // Return success code
+  return 0;
+}
diff --git a/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp b/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ebc63e28ff3abfd265525c0ec2e1dc9adddc05a9
--- /dev/null
+++ b/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp
@@ -0,0 +1,223 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2018 Acts project team
+//
+// 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 <boost/program_options.hpp>
+#include <memory>
+#include "ACTFW/Framework/Sequencer.hpp"
+#include "ACTFW/Geometry/CommonGeometry.hpp"
+#include "ACTFW/Options/CommonOptions.hpp"
+#include "ACTFW/Plugins/BField/BFieldOptions.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp"
+#include "ACTFW/Propagation/PropagationAlgorithm.hpp"
+#include "ACTFW/Propagation/PropagationOptions.hpp"
+#include "ACTFW/Random/RandomNumbersOptions.hpp"
+#include "ACTFW/Random/RandomNumbersSvc.hpp"
+#include "ACTFW/Utilities/Paths.hpp"
+#include "Acts/Detector/TrackingGeometry.hpp"
+#include "Acts/Extrapolator/Navigator.hpp"
+#include "Acts/MagneticField/ConstantBField.hpp"
+#include "Acts/MagneticField/InterpolatedBFieldMap.hpp"
+#include "Acts/MagneticField/SharedBField.hpp"
+#include "Acts/Propagator/EigenStepper.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/StraightLineStepper.hpp"
+
+namespace po = boost::program_options;
+
+/// @brief Propagation setup
+///
+/// @tparam sequencer_t Type of the sequencer of the framework
+/// @tparam bfield_t Type of the magnetic field
+///
+/// @param sequencer The framework sequencer, Propagation algorithm to be added
+/// @param bfield The bfield object needed for the Stepper & propagagor
+/// @param vm The program options for the log file
+/// @param randomNumberSvc The framework random number engine
+/// @param tGeometry The TrackingGeometry object
+///
+/// @return a process code
+template <typename sequencer_t, typename bfield_t>
+FW::ProcessCode
+setupPropagation(sequencer_t&                                  sequencer,
+                 bfield_t                                      bfield,
+                 po::variables_map&                            vm,
+                 std::shared_ptr<FW::RandomNumbersSvc>         randomNumberSvc,
+                 std::shared_ptr<const Acts::TrackingGeometry> tGeometry)
+{
+  // Get the log level
+  auto logLevel = FW::Options::readLogLevel(vm);
+
+  // Get a Navigator
+  Acts::Navigator navigator(tGeometry);
+
+  // Resolve the bfield map template and create the propgator
+  using Stepper    = Acts::EigenStepper<bfield_t>;
+  using Propagator = Acts::Propagator<Stepper, Acts::Navigator>;
+  Stepper    stepper(std::move(bfield));
+  Propagator propagator(std::move(stepper), std::move(navigator));
+
+  // Read the propagation config and create the algorithms
+  auto pAlgConfig = FW::Options::readPropagationConfig(vm, propagator);
+  pAlgConfig.randomNumberSvc = randomNumberSvc;
+  auto propagationAlg = std::make_shared<FW::PropagationAlgorithm<Propagator>>(
+      pAlgConfig, logLevel);
+
+  // Add the propagation algorithm
+  sequencer.addAlgorithm({propagationAlg});
+
+  return FW::ProcessCode::SUCCESS;
+}
+
+/// @brief Straight Line Propagation setup
+///
+/// @tparam sequencer_t Type of the sequencer of the framework
+///
+/// @param sequencer The framework sequencer, Propagation algorithm to be added
+/// @param vm The program options for the log file
+/// @param randomNumberSvc The framework random number engine
+/// @param tGeometry The TrackingGeometry object
+///
+/// @return a process code
+template <typename sequencer_t>
+FW::ProcessCode
+setupStraightLinePropagation(
+    sequencer_t&                                  sequencer,
+    po::variables_map&                            vm,
+    std::shared_ptr<FW::RandomNumbersSvc>         randomNumberSvc,
+    std::shared_ptr<const Acts::TrackingGeometry> tGeometry)
+{
+  // Get the log level
+  auto logLevel = FW::Options::readLogLevel(vm);
+
+  // Get a Navigator
+  Acts::Navigator navigator(tGeometry);
+
+  // Straight line stepper
+  using SlStepper  = Acts::StraightLineStepper;
+  using Propagator = Acts::Propagator<SlStepper, Acts::Navigator>;
+  // Make stepper and propagator
+  SlStepper  stepper;
+  Propagator propagator(std::move(stepper), std::move(navigator));
+
+  // Read the propagation config and create the algorithms
+  auto pAlgConfig = FW::Options::readPropagationConfig(vm, propagator);
+  pAlgConfig.randomNumberSvc = randomNumberSvc;
+  auto propagationAlg = std::make_shared<FW::PropagationAlgorithm<Propagator>>(
+      pAlgConfig, logLevel);
+
+  // Add the propagation algorithm
+  sequencer.addAlgorithm({propagationAlg});
+
+  return FW::ProcessCode::SUCCESS;
+}
+
+/// @brief The material validation example, it runs a propagation
+/// and then writes out the material information
+///
+/// @tparam options_setup_t Type of the options generator
+/// @tparam geometry_setup_t Type of the geometry generator
+///
+/// @param argc the number of argumetns of the call
+/// @param atgv the argument list
+///
+///
+/// @param optionsSetup is a struct to generate example specific options
+/// @param geometrySteup is a struct to generate the geometry
+template <typename options_setup_t, typename geometry_setup_t>
+int
+materialValidationExample(int              argc,
+                          char*            argv[],
+                          options_setup_t  optionsSetup,
+                          geometry_setup_t geometrySetup)
+{
+
+  // Setup and parse options
+  auto desc = FW::Options::makeDefaultOptions();
+  FW::Options::addSequencerOptions(desc);
+  FW::Options::addGeometryOptions(desc);
+  FW::Options::addMaterialOptions(desc);
+  FW::Options::addBFieldOptions(desc);
+  FW::Options::addRandomNumbersOptions(desc);
+  FW::Options::addPropagationOptions(desc);
+  FW::Options::addOutputOptions(desc);
+
+  // Add specific options for this geometry
+  optionsSetup(desc);
+  auto vm = FW::Options::parse(desc, argc, argv);
+  if (vm.empty()) {
+    return EXIT_FAILURE;
+  }
+
+  FW::Sequencer sequencer(FW::Options::readSequencerConfig(vm));
+
+  // Now read the standard options
+  auto logLevel = FW::Options::readLogLevel(vm);
+
+  // The geometry, material and decoration
+  auto geometry          = FW::Geometry::build(vm, geometrySetup);
+  auto tGeometry         = geometry.first;
+  auto contextDecorators = geometry.second;
+
+  // Create the random number engine
+  auto randomNumberSvcCfg = FW::Options::readRandomNumbersConfig(vm);
+  auto randomNumberSvc
+      = std::make_shared<FW::RandomNumbersSvc>(randomNumberSvcCfg);
+  // Add it to the sequencer
+  sequencer.addService(randomNumberSvc);
+
+  // Create BField service
+  auto bField  = FW::Options::readBField<po::variables_map>(vm);
+  auto field2D = std::get<std::shared_ptr<InterpolatedBFieldMap2D>>(bField);
+  auto field3D = std::get<std::shared_ptr<InterpolatedBFieldMap3D>>(bField);
+  auto fieldC  = std::get<std::shared_ptr<Acts::ConstantBField>>(bField);
+
+  if (vm["prop-stepper"].template as<int>() == 0) {
+    // Straight line stepper was chosen
+    setupStraightLinePropagation(sequencer, vm, randomNumberSvc, tGeometry);
+  } else if (field2D) {
+    // Define the interpolated b-field: 2D
+    using BField = Acts::SharedBField<InterpolatedBFieldMap2D>;
+    BField fieldMap(field2D);
+    setupPropagation(sequencer, fieldMap, vm, randomNumberSvc, tGeometry);
+  } else if (field3D) {
+    // Define the interpolated b-field: 3D
+    using BField = Acts::SharedBField<InterpolatedBFieldMap3D>;
+    BField fieldMap(field3D);
+    setupPropagation(sequencer, fieldMap, vm, randomNumberSvc, tGeometry);
+  } else {
+    // Create the constant  field
+    using CField = Acts::ConstantBField;
+    CField fieldMap(*std::get<std::shared_ptr<CField>>(bField));
+    // Create the constant  field
+    setupPropagation(sequencer, fieldMap, vm, randomNumberSvc, tGeometry);
+  }
+
+  // ---------------------------------------------------------------------------------
+  // Output directory
+  std::string outputDir     = vm["output-dir"].template as<std::string>();
+  auto        matCollection = vm["prop-material-collection"].as<std::string>();
+
+  if (vm["output-root"].template as<bool>()) {
+    // Write the propagation steps as ROOT TTree
+    FW::Root::RootMaterialTrackWriter::Config matTrackWriterRootConfig;
+    matTrackWriterRootConfig.collection = matCollection;
+    matTrackWriterRootConfig.filePath
+        = FW::joinPaths(outputDir, matCollection + ".root");
+    auto matTrackWriterRoot
+        = std::make_shared<FW::Root::RootMaterialTrackWriter>(
+            matTrackWriterRootConfig, logLevel);
+    sequencer.addWriter(matTrackWriterRoot);
+  }
+
+  // Initiate the run
+  sequencer.run();
+  // Return success code
+  return 0;
+}
diff --git a/Examples/Propagation/CMakeLists.txt b/Examples/Propagation/CMakeLists.txt
index 717abb06860d3f2b27ecbef4b40ee375ec53477e..049d55e60dcc5064b7b06cff870bd8a6e15d5184 100755
--- a/Examples/Propagation/CMakeLists.txt
+++ b/Examples/Propagation/CMakeLists.txt
@@ -1,57 +1,71 @@
+set(_common_libraries
+  ActsCore
+  ACTFramework
+  ACTFWPropagation
+  ACTFWExamplesCommon
+  ACTFWBFieldPlugin
+  ACTFWObjPlugin
+  ACTFWJsonPlugin
+  ACTFWRootPlugin
+  ${Boost_LIBRARIES})
+
 # Generic detector
 add_executable(ACTFWGenericPropagationExample src/GenericPropagationExample.cpp)
-target_include_directories(ACTFWGenericPropagationExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWGenericPropagationExample PRIVATE ActsCore)
-target_link_libraries(ACTFWGenericPropagationExample PRIVATE ACTFramework ACTFWExamplesCommon ACTFWPropagation ACTFWGenericDetector)
-target_link_libraries(ACTFWGenericPropagationExample PRIVATE ACTFWRootPlugin ACTFWObjPlugin ACTFWBFieldPlugin)
-target_link_libraries(ACTFWGenericPropagationExample PRIVATE ${Boost_LIBRARIES})
-
-install(TARGETS ACTFWGenericPropagationExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+target_include_directories(ACTFWGenericPropagationExample PRIVATE
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWGenericPropagationExample PRIVATE
+  ${_common_libraries}
+  ACTFWGenericDetector)
+install(
+  TARGETS ACTFWGenericPropagationExample
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # Generic detector with IOV based alignment
 add_executable(ACTFWAlignedPropagationExample src/AlignedPropagationExample.cpp)
-target_include_directories(ACTFWAlignedPropagationExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWAlignedPropagationExample PRIVATE ActsCore)
-target_link_libraries(ACTFWAlignedPropagationExample PRIVATE ACTFramework ACTFWExamplesCommon ACTFWPropagation)
-target_link_libraries(ACTFWAlignedPropagationExample PRIVATE ACTFWGenericDetector ACTFWContextualDetector)
-target_link_libraries(ACTFWAlignedPropagationExample PRIVATE ACTFWRootPlugin ACTFWObjPlugin ACTFWBFieldPlugin)
-target_link_libraries(ACTFWAlignedPropagationExample PRIVATE ${Boost_LIBRARIES})
-
-install(TARGETS ACTFWAlignedPropagationExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+target_include_directories(ACTFWAlignedPropagationExample PRIVATE
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWAlignedPropagationExample PRIVATE
+  ${_common_libraries}
+  ACTFWContextualDetector)
+install(
+  TARGETS ACTFWAlignedPropagationExample
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-# Generic detector with payload based alignment
+# Generic detector with Payload based alignment
 add_executable(ACTFWPayloadPropagationExample src/PayloadPropagationExample.cpp)
-target_include_directories(ACTFWPayloadPropagationExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWPayloadPropagationExample PRIVATE ActsCore)
-target_link_libraries(ACTFWPayloadPropagationExample PRIVATE ACTFramework ACTFWExamplesCommon ACTFWPropagation)
-target_link_libraries(ACTFWPayloadPropagationExample PRIVATE ACTFWGenericDetector ACTFWContextualDetector)
-target_link_libraries(ACTFWPayloadPropagationExample PRIVATE ACTFWRootPlugin ACTFWObjPlugin ACTFWBFieldPlugin)
-target_link_libraries(ACTFWPayloadPropagationExample PRIVATE ${Boost_LIBRARIES})
-
-install(TARGETS ACTFWPayloadPropagationExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+target_include_directories(ACTFWPayloadPropagationExample PRIVATE
+  ${Boost_INCLUDE_DIRS})
+target_link_libraries(ACTFWPayloadPropagationExample PRIVATE
+  ${_common_libraries}
+  ACTFWContextualDetector)
+install(
+  TARGETS ACTFWPayloadPropagationExample
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # TGEO based detector
 if (USE_TGEO)
   add_executable(ACTFWTGeoPropagationExample src/TGeoPropagationExample.cpp)
-  target_include_directories(ACTFWTGeoPropagationExample PRIVATE ${Boost_INCLUDE_DIRS})
-  target_link_libraries(ACTFWTGeoPropagationExample PRIVATE ActsCore)
-  target_link_libraries(ACTFWTGeoPropagationExample PRIVATE ACTFramework ACTFWExamplesCommon ACTFWPropagation ACTFWTGeoDetector)
-  target_link_libraries(ACTFWTGeoPropagationExample PRIVATE ACTFWRootPlugin ACTFWObjPlugin ACTFWBFieldPlugin)
-  target_link_libraries(ACTFWTGeoPropagationExample PRIVATE ${Boost_LIBRARIES})
-
-  install(TARGETS ACTFWTGeoPropagationExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+  target_include_directories(ACTFWTGeoPropagationExample PRIVATE
+    ${Boost_INCLUDE_DIRS})
+  target_link_libraries(ACTFWTGeoPropagationExample PRIVATE
+    ${_common_libraries}
+    ACTFWTGeoDetector ACTFWGeometryInterfaces)
+  install(
+    TARGETS ACTFWTGeoPropagationExample
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
 
 # DD4hep detector
 if (USE_DD4HEP)
   add_executable(ACTFWDD4hepPropagationExample src/DD4hepPropagationExample.cpp)
-  target_include_directories(ACTFWDD4hepPropagationExample PRIVATE ${DD4hep_INCLUDE_DIRS})
-  target_include_directories(ACTFWDD4hepPropagationExample PRIVATE ${Boost_INCLUDE_DIRS})  
-  target_link_libraries(ACTFWDD4hepPropagationExample PRIVATE ActsCore)
-  target_link_libraries(ACTFWDD4hepPropagationExample PRIVATE ACTFramework ACTFWExamplesCommon ACTFWPropagation ACTFWDD4hepDetector)
-  target_link_libraries(ACTFWDD4hepPropagationExample PRIVATE ACTFWRootPlugin ACTFWObjPlugin ACTFWBFieldPlugin)
-  target_link_libraries(ACTFWDD4hepPropagationExample PRIVATE ${DD4hep_LIBRARIES})
-  target_link_libraries(ACTFWDD4hepPropagationExample PRIVATE ${Boost_LIBRARIES})
-
-  install(TARGETS ACTFWDD4hepPropagationExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+  target_include_directories(ACTFWDD4hepPropagationExample PRIVATE
+    ${Boost_INCLUDE_DIRS}
+    ${DD4hep_INCLUDE_DIRS})
+  target_link_libraries(ACTFWDD4hepPropagationExample PRIVATE
+    ${_common_libraries}
+    ACTFWDD4hepDetector ACTFWGeometryInterfaces
+    ${DD4hep_LIBRARIES})
+  install(
+    TARGETS ACTFWDD4hepPropagationExample
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
diff --git a/Examples/Propagation/src/detail/PropagationExampleBase.hpp b/Examples/Propagation/src/detail/PropagationExampleBase.hpp
index 42542d1549df155a798c2010733f8b33a617e7bd..743ccde0b6c1391fc697d6ddae7dcfc600dd362b 100644
--- a/Examples/Propagation/src/detail/PropagationExampleBase.hpp
+++ b/Examples/Propagation/src/detail/PropagationExampleBase.hpp
@@ -13,6 +13,7 @@
 #include <boost/program_options.hpp>
 
 #include "ACTFW/Framework/Sequencer.hpp"
+#include "ACTFW/Geometry/CommonGeometry.hpp"
 #include "ACTFW/Options/CommonOptions.hpp"
 #include "ACTFW/Plugins/BField/BFieldOptions.hpp"
 #include "ACTFW/Plugins/BField/ScalableBField.hpp"
@@ -130,30 +131,32 @@ propagationExample(int               argc,
                    options_setup_t&  optionsSetup,
                    geometry_setup_t& geometrySetup)
 {
-  // setup and parse options
+  // Setup and parse options
   auto desc = FW::Options::makeDefaultOptions();
   FW::Options::addSequencerOptions(desc);
   FW::Options::addGeometryOptions(desc);
+  FW::Options::addMaterialOptions(desc);
   FW::Options::addBFieldOptions(desc);
   FW::Options::addRandomNumbersOptions(desc);
   FW::Options::addPropagationOptions(desc);
   FW::Options::addOutputOptions(desc);
+
   // Add specific options for this geometry
   optionsSetup(desc);
   auto vm = FW::Options::parse(desc, argc, argv);
   if (vm.empty()) {
     return EXIT_FAILURE;
   }
-
   FW::Sequencer sequencer(FW::Options::readSequencerConfig(vm));
 
   // Now read the standard options
-  auto logLevel          = FW::Options::readLogLevel(vm);
-  auto geometry          = geometrySetup(vm);
+  auto logLevel = FW::Options::readLogLevel(vm);
+
+  // The geometry, material and decoration
+  auto geometry          = FW::Geometry::build(vm, geometrySetup);
   auto tGeometry         = geometry.first;
   auto contextDecorators = geometry.second;
-
-  // Add it to the sequencer
+  // Add the decorator to the sequencer
   for (auto cdr : contextDecorators) {
     sequencer.addContextDecorator(cdr);
   }
diff --git a/Plugins/CMakeLists.txt b/Plugins/CMakeLists.txt
index 40755da18e79f5b741275fe40fb17f2d12a21f32..6b1965c6ec1197388e39e630dbe6e18fb88be49b 100644
--- a/Plugins/CMakeLists.txt
+++ b/Plugins/CMakeLists.txt
@@ -1,9 +1,9 @@
 add_subdirectory(BField)
 add_subdirectory(Csv)
-#add_subdirectory_if(DD4hepG4 USE_DD4HEP AND USE_GEANT4)
+add_subdirectory_if(DD4hepG4 USE_DD4HEP AND USE_GEANT4)
 add_subdirectory_if(Geant4 USE_GEANT4)
-#add_subdirectory(Json)
+add_subdirectory(Json)
 add_subdirectory(Obj)
 add_subdirectory_if(Pythia8 USE_PYTHIA8)
 add_subdirectory(Root)
-add_subdirectory_if(HepMC USE_HEPMC3)
\ No newline at end of file
+add_subdirectory_if(HepMC USE_HEPMC3)
diff --git a/Plugins/DD4hepG4/CMakeLists.txt b/Plugins/DD4hepG4/CMakeLists.txt
index 8a6eec5c805da2e73105b8f5b8694b27b4d7542b..c732647d968b354829c10f7b8318b20e91a95738 100644
--- a/Plugins/DD4hepG4/CMakeLists.txt
+++ b/Plugins/DD4hepG4/CMakeLists.txt
@@ -6,7 +6,7 @@ add_library(ACTFWDD4hepG4Plugin SHARED ${src_files})
 target_include_directories(ACTFWDD4hepG4Plugin PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/> $<INSTALL_INTERFACE:include>)
 target_include_directories(ACTFWDD4hepG4Plugin PUBLIC ${DD4hep_INCLUDE_DIRS})
 target_include_directories(ACTFWDD4hepG4Plugin PUBLIC ${ROOT_INCLUDE_DIRS})
-target_link_libraries(ACTFWDD4hepG4Plugin PUBLIC ACTFramework)
+target_link_libraries(ACTFWDD4hepG4Plugin PUBLIC ACTFramework ACTFWGeometryInterfaces)
 target_link_libraries(ACTFWDD4hepG4Plugin PUBLIC ${DD4hep_LIBRARIES} ${DD4hep_DDG4_LIBRARY})
 target_link_libraries(ACTFWDD4hepG4Plugin PUBLIC ${Geant4_LIBRARIES})
 target_link_libraries(ACTFWDD4hepG4Plugin PUBLIC ${ROOT_LIBRARIES})
diff --git a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMDetectorConstruction.hpp b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMDetectorConstruction.hpp
index ae118893f43b3083fb867a7542c2c6e8b35abb19..099c170e61d43f686c3ceac2645f55b957f58537 100644
--- a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMDetectorConstruction.hpp
+++ b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMDetectorConstruction.hpp
@@ -6,8 +6,7 @@
 // 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/.
 
-#ifndef ACTFW_PLUGINS_GEANT4_MMDETECTORCONSTRUCTION_H
-#define ACTFW_PLUGINS_GEANT4_MMDETECTORCONSTRUCTION_H
+#pragma once
 
 #include "G4VUserDetectorConstruction.hh"
 #include "globals.hh"
@@ -19,7 +18,7 @@ class G4VPhysicalVolume;
 class TGeoNode;
 
 namespace FW {
-namespace G4 {
+namespace Geant4 {
 
   /// @class MMDetectorConstruction
   ///
@@ -56,5 +55,3 @@ namespace G4 {
   };
 }  // namespace G4
 }  // namespace FW
-
-#endif  // ACTFW_PLUGINS_GEANT4_MMDETECTORCONSTRUCTION_H
diff --git a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMEventAction.hpp b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMEventAction.hpp
index 3b2dab0b111c0670ba57f7dda124b3e2e0b1abb4..0bd5252241d1bc2867c35a7412f592cb47a98160 100644
--- a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMEventAction.hpp
+++ b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMEventAction.hpp
@@ -1,26 +1,26 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2018 Acts project team
 //
 // 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/.
 
 ///////////////////////////////////////////////////////////////////
-// MMEventAction.h
+// MMEventAction.hpp
 ///////////////////////////////////////////////////////////////////
 
-#ifndef ACTFW_PLUGINS_GEANT4_MMEVENTACTION_H
-#define ACTFW_PLUGINS_GEANT4_MMEVENTACTION_H
+#pragma once
 
 #include <memory>
-#include "Acts/Plugins/MaterialMapping/RecordedMaterialTrack.hpp"
+#include "Acts/Extrapolator/MaterialInteractor.hpp"
 #include "G4UserEventAction.hh"
 #include "globals.hh"
 
-/// @namespace FW::G4:: Namespace for geant4 material mapping
+/// @namespace FW::Geant4:: Namespace for geant4 material mapping
 namespace FW {
-namespace G4 {
+
+namespace Geant4 {
 
   class MMSteppingAction;
 
@@ -81,7 +81,5 @@ namespace G4 {
     m_records.clear();
     return rrecords;
   }
-}  // namespace G4
+}  // namespace Geant4
 }  // namespace FW
-
-#endif  // ACTFW_PLUGINS_GEANT4_MMEVENTACTION_H
diff --git a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMPrimaryGeneratorAction.hpp b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMPrimaryGeneratorAction.hpp
index bc9a038b5187195e5058e8609e4e182d365765f4..12402a8875d9cd30981e57fd0eb3c65d5f64865e 100644
--- a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMPrimaryGeneratorAction.hpp
+++ b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMPrimaryGeneratorAction.hpp
@@ -7,11 +7,10 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 ///////////////////////////////////////////////////////////////////
-// MMPrimaryGeneratorAction.h
+// MMPrimaryGeneratorAction.hpp
 ///////////////////////////////////////////////////////////////////
 
-#ifndef ACTFW_PLUGINS_GEANT4_MMPRIMARYGENERATORACTION_H
-#define ACTFW_PLUGINS_GEANT4_MMPRIMARYGENERATORACTION_H
+#pragma once
 
 #include <memory>
 #include "G4SystemOfUnits.hh"
@@ -23,7 +22,7 @@ class G4ParticleGun;
 class G4Event;
 
 namespace FW {
-namespace G4 {
+namespace Geant4 {
 
   /// @class MMPrimaryGeneratorAction
   ///
@@ -82,5 +81,3 @@ namespace G4 {
 
 }  // namespace G4
 }  // namespace FW
-
-#endif  // GEANT4MATERIALMAPPING_MMPRIMARYGENERATORACTION_H
diff --git a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMRunAction.hpp b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMRunAction.hpp
index 536961f160d38796d52be3a5cfe10bc088dfbefb..cea996a87972fb90943843330368f069b09378fa 100644
--- a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMRunAction.hpp
+++ b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMRunAction.hpp
@@ -7,11 +7,10 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 ///////////////////////////////////////////////////////////////////
-// MMRunAction.h
+// MMRunAction.hpp
 ///////////////////////////////////////////////////////////////////
 
-#ifndef ACTFW_PLUGINS_GEANT4_MMRUNACTION_H
-#define ACTFW_PLUGINS_GEANT4_MMRUNACTION_H
+#pragma once
 
 #include <memory>
 #include "G4UserRunAction.hh"
@@ -20,7 +19,7 @@
 class G4Run;
 
 namespace FW {
-namespace G4 {
+namespace Geant4 {
 
   /// @class MMRunAction
   ///
@@ -58,5 +57,3 @@ namespace G4 {
   };
 }  // namespace G4
 }  // namespace FW
-
-#endif  // ACTFW_PLUGINS_GEANT4_MMRUNACTION_H
diff --git a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMSteppingAction.hpp b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMSteppingAction.hpp
index f1be5ba8ff63f29cd2d16004972a85286fe8de2e..9d3ab9648b36b19ba7b9c25f6d5449720ffbcc61 100644
--- a/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMSteppingAction.hpp
+++ b/Plugins/Geant4/include/ACTFW/Plugins/Geant4/MMSteppingAction.hpp
@@ -1,34 +1,32 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2018 Acts project team
 //
 // 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/.
 
 ///////////////////////////////////////////////////////////////////
-// MMMaterialStepAction.h
+// MMMaterialStepAction.hpp
 ///////////////////////////////////////////////////////////////////
 
-#ifndef ACTFW_PLUGINS_GEANT4_MMSTEPPINGACTION_H
-#define ACTFW_PLUGINS_GEANT4_MMSTEPPINGACTION_H
+#pragma once
 
 #include <vector>
-#include "Acts/Plugins/MaterialMapping/RecordedMaterialTrack.hpp"
+#include "Acts/Extrapolator/MaterialInteractor.hpp"
 #include "G4UserSteppingAction.hh"
 #include "globals.hh"
 
 namespace FW {
-namespace G4 {
+namespace Geant4 {
 
   /// @class MMSteppingAction
   ///
   /// @brief Collects the RecordedMaterialProperties entities
   ///
   /// The MMSteppingAction class is the implementation of the
-  /// Geant4 class SteppingAction. It creates extracts the weighted material
+  /// Geant4 class SteppingAction. It extracts the weighted material
   /// of every step and collects all material steps.
-
   class MMSteppingAction : public G4UserSteppingAction
   {
   public:
@@ -38,12 +36,12 @@ namespace G4 {
     /// Destructor
     ~MMSteppingAction() override;
 
-    /// Static access method
+    /// Static access method to the instance
     static MMSteppingAction*
     Instance();
 
-    /// Interface Method doing the step
-    /// @note it creates and collects the RecordedMaterialProperties entities
+    /// @brief Interface Method doing the step
+    /// @note it creates and collects the MaterialInteraction entities
     /// @param step is the Geant4 step of the particle
     void
     UserSteppingAction(const G4Step* step) final override;
@@ -53,8 +51,8 @@ namespace G4 {
     void
     Reset();
 
-    /// Access to the collected RecordedMaterialProperties entities
-    std::vector<Acts::RecordedMaterialProperties>
+    /// Access to the collected Acts::MaterialInteraction entities
+    std::vector<Acts::MaterialInteraction>
     materialSteps()
     {
       return m_steps;
@@ -64,11 +62,9 @@ namespace G4 {
     /// Instance of the SteppingAction
     static MMSteppingAction* fgInstance;
 
-    /// The collected RecordedMaterialProperties entities
-    std::vector<Acts::RecordedMaterialProperties> m_steps;
+    /// The collected Acts::MaterialInteraction entities
+    std::vector<Acts::MaterialInteraction> m_steps = {};
   };
 
-}  // namespace G4
+}  // namespace Geant4
 }  // namespace FW
-
-#endif  // ACTFW_PLUGINS_GEANT4_MMSTEPPINGACTION_H
diff --git a/Plugins/Geant4/src/MMDetectorConstruction.cpp b/Plugins/Geant4/src/MMDetectorConstruction.cpp
index 40fa3d29f5cd49736a28897727f732b3484da9c1..15e6efc4c1e422cb5e3e135c5ed9209d61296024 100644
--- a/Plugins/Geant4/src/MMDetectorConstruction.cpp
+++ b/Plugins/Geant4/src/MMDetectorConstruction.cpp
@@ -10,13 +10,13 @@
 #include "G4GDMLParser.hh"
 #include "TGeoManager.h"
 
-FW::G4::MMDetectorConstruction::MMDetectorConstruction()
+FW::Geant4::MMDetectorConstruction::MMDetectorConstruction()
   : G4VUserDetectorConstruction(), m_tgeoNode(nullptr), m_gdmlFile(nullptr)
 {
 }
 
 G4VPhysicalVolume*
-FW::G4::MMDetectorConstruction::Construct()
+FW::Geant4::MMDetectorConstruction::Construct()
 {
   if (m_tgeoNode) {
     // Import geometry from Root to VGM
@@ -40,13 +40,13 @@ FW::G4::MMDetectorConstruction::Construct()
 }
 
 void
-FW::G4::MMDetectorConstruction::setTGeoGeometry(TGeoNode* tgeoNode)
+FW::Geant4::MMDetectorConstruction::setTGeoGeometry(TGeoNode* tgeoNode)
 {
   m_tgeoNode = tgeoNode;
 }
 
 void
-FW::G4::MMDetectorConstruction::setGdmlInput(std::string gdmlFile)
+FW::Geant4::MMDetectorConstruction::setGdmlInput(std::string gdmlFile)
 {
   m_gdmlFile = new std::string(gdmlFile);
 }
diff --git a/Plugins/Geant4/src/MMEventAction.cpp b/Plugins/Geant4/src/MMEventAction.cpp
index f4b8e66f1208231aac4724e871f9f1b06246057f..cd528f2c0b1242c52f0ca41db2e68844ef2ec292 100644
--- a/Plugins/Geant4/src/MMEventAction.cpp
+++ b/Plugins/Geant4/src/MMEventAction.cpp
@@ -1,6 +1,6 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2018 Acts project team
 //
 // 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
@@ -13,16 +13,16 @@
 #include "G4Event.hh"
 #include "G4RunManager.hh"
 
-FW::G4::MMEventAction* FW::G4::MMEventAction::fgInstance = nullptr;
+FW::Geant4::MMEventAction* FW::Geant4::MMEventAction::fgInstance = nullptr;
 
-FW::G4::MMEventAction*
-FW::G4::MMEventAction::Instance()
+FW::Geant4::MMEventAction*
+FW::Geant4::MMEventAction::Instance()
 {
   // Static acces function via G4RunManager
   return fgInstance;
 }
 
-FW::G4::MMEventAction::MMEventAction() : G4UserEventAction()
+FW::Geant4::MMEventAction::MMEventAction() : G4UserEventAction()
 {
   if (fgInstance) {
     throw std::logic_error("Attempted to duplicate a singleton");
@@ -31,34 +31,38 @@ FW::G4::MMEventAction::MMEventAction() : G4UserEventAction()
   }
 }
 
-FW::G4::MMEventAction::~MMEventAction()
+FW::Geant4::MMEventAction::~MMEventAction()
 {
   fgInstance = nullptr;
 }
 
 void
-FW::G4::MMEventAction::BeginOfEventAction(const G4Event*)
+FW::Geant4::MMEventAction::BeginOfEventAction(const G4Event*)
 {
   // reset the collection of material steps
   MMSteppingAction::Instance()->Reset();
 }
 
 void
-FW::G4::MMEventAction::EndOfEventAction(const G4Event* event)
+FW::Geant4::MMEventAction::EndOfEventAction(const G4Event* event)
 {
-  const auto*          rawPos = event->GetPrimaryVertex();
-  const Acts::Vector3D pos(rawPos->GetX0(), rawPos->GetY0(), rawPos->GetZ0());
+
+  const auto* rawPos = event->GetPrimaryVertex();
   // access the initial direction of the track
   G4ThreeVector rawDir = MMPrimaryGeneratorAction::Instance()->direction();
-  const Acts::Vector3D dir(rawDir.x(), rawDir.y(), rawDir.z());
   // create the RecordedMaterialTrack
-  Acts::RecordedMaterialTrack mtrecord(
-      pos, dir, MMSteppingAction::Instance()->materialSteps());
+  Acts::RecordedMaterialTrack mtrecord;
+  mtrecord.first.first
+      = Acts::Vector3D(rawPos->GetX0(), rawPos->GetY0(), rawPos->GetZ0());
+  mtrecord.first.second = Acts::Vector3D(rawDir.x(), rawDir.y(), rawDir.z());
+  mtrecord.second.materialInteractions
+      = MMSteppingAction::Instance()->materialSteps();
+
   // write out the RecordedMaterialTrack of one event
   m_records.push_back(mtrecord);
 }
 
 void
-FW::G4::MMEventAction::Reset()
+FW::Geant4::MMEventAction::Reset()
 {
 }
diff --git a/Plugins/Geant4/src/MMPrimaryGeneratorAction.cpp b/Plugins/Geant4/src/MMPrimaryGeneratorAction.cpp
index 58afaa9daa998c2964b2c66ccc67387bf988b9bf..034c44ff2b3e9c5fdd513d16ee6f3d4f4f93e55d 100644
--- a/Plugins/Geant4/src/MMPrimaryGeneratorAction.cpp
+++ b/Plugins/Geant4/src/MMPrimaryGeneratorAction.cpp
@@ -16,10 +16,11 @@
 #include "G4UnitsTable.hh"
 #include "Randomize.hh"
 
-FW::G4::MMPrimaryGeneratorAction* FW::G4::MMPrimaryGeneratorAction::fgInstance
+FW::Geant4::MMPrimaryGeneratorAction*
+    FW::Geant4::MMPrimaryGeneratorAction::fgInstance
     = nullptr;
 
-FW::G4::MMPrimaryGeneratorAction::MMPrimaryGeneratorAction(
+FW::Geant4::MMPrimaryGeneratorAction::MMPrimaryGeneratorAction(
     const G4String& particleName,
     G4double        energy,
     G4int           randomSeed1,
@@ -46,20 +47,20 @@ FW::G4::MMPrimaryGeneratorAction::MMPrimaryGeneratorAction(
   CLHEP::HepRandom::getTheEngine()->setSeed(randomSeed1, randomSeed2);
 }
 
-FW::G4::MMPrimaryGeneratorAction::~MMPrimaryGeneratorAction()
+FW::Geant4::MMPrimaryGeneratorAction::~MMPrimaryGeneratorAction()
 {
   fgInstance = nullptr;
 }
 
-FW::G4::MMPrimaryGeneratorAction*
-FW::G4::MMPrimaryGeneratorAction::Instance()
+FW::Geant4::MMPrimaryGeneratorAction*
+FW::Geant4::MMPrimaryGeneratorAction::Instance()
 {
   // Static acces function via G4RunManager
   return fgInstance;
 }
 
 void
-FW::G4::MMPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent)
+FW::Geant4::MMPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent)
 {
   // this function is called at the begining of event
   G4double phi   = -M_PI + G4UniformRand() * 2. * M_PI;
diff --git a/Plugins/Geant4/src/MMRunAction.cpp b/Plugins/Geant4/src/MMRunAction.cpp
index 7d4c5ee81c68ca7ad61f17dcc76b6faf661a96e3..2a1534b0eb8cd547a9c1d873fcc57fb0836d39ae 100644
--- a/Plugins/Geant4/src/MMRunAction.cpp
+++ b/Plugins/Geant4/src/MMRunAction.cpp
@@ -11,9 +11,9 @@
 #include "ACTFW/Plugins/Geant4/MMEventAction.hpp"
 #include "G4Run.hh"
 
-FW::G4::MMRunAction* FW::G4::MMRunAction::fgInstance = nullptr;
+FW::Geant4::MMRunAction* FW::Geant4::MMRunAction::fgInstance = nullptr;
 
-FW::G4::MMRunAction::MMRunAction() : G4UserRunAction()
+FW::Geant4::MMRunAction::MMRunAction() : G4UserRunAction()
 {
   if (fgInstance) {
     throw std::logic_error("Attempted to duplicate a singleton");
@@ -22,19 +22,19 @@ FW::G4::MMRunAction::MMRunAction() : G4UserRunAction()
   }
 }
 
-FW::G4::MMRunAction::~MMRunAction()
+FW::Geant4::MMRunAction::~MMRunAction()
 {
   fgInstance = nullptr;
 }
 
-FW::G4::MMRunAction*
-FW::G4::MMRunAction::Instance()
+FW::Geant4::MMRunAction*
+FW::Geant4::MMRunAction::Instance()
 {
   return fgInstance;
 }
 
 void
-FW::G4::MMRunAction::BeginOfRunAction(const G4Run* aRun)
+FW::Geant4::MMRunAction::BeginOfRunAction(const G4Run* aRun)
 {
   G4cout << "### Run " << aRun->GetRunID() << " start." << G4endl;
   // initialize event cumulative quantities
@@ -42,7 +42,7 @@ FW::G4::MMRunAction::BeginOfRunAction(const G4Run* aRun)
 }
 
 void
-FW::G4::MMRunAction::EndOfRunAction(const G4Run* aRun)
+FW::Geant4::MMRunAction::EndOfRunAction(const G4Run* aRun)
 {
   G4int nofEvents = aRun->GetNumberOfEvent();
   if (nofEvents == 0) return;
diff --git a/Plugins/Geant4/src/MMSteppingAction.cpp b/Plugins/Geant4/src/MMSteppingAction.cpp
index 16d6fbcab56ceaaf3ecd50223db35d802f501870..f5f3884eb11284690306bf51c539a0d0846a3044 100644
--- a/Plugins/Geant4/src/MMSteppingAction.cpp
+++ b/Plugins/Geant4/src/MMSteppingAction.cpp
@@ -1,6 +1,6 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2017 Acts project team
+// Copyright (C) 2017-2018 Acts project team
 //
 // 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
@@ -12,16 +12,18 @@
 #include "G4Material.hh"
 #include "G4Step.hh"
 
-FW::G4::MMSteppingAction* FW::G4::MMSteppingAction::fgInstance = nullptr;
+FW::Geant4::MMSteppingAction* FW::Geant4::MMSteppingAction::fgInstance
+    = nullptr;
 
-FW::G4::MMSteppingAction*
-FW::G4::MMSteppingAction::Instance()
+FW::Geant4::MMSteppingAction*
+FW::Geant4::MMSteppingAction::Instance()
 {
   // Static acces function via G4RunManager
   return fgInstance;
 }
 
-FW::G4::MMSteppingAction::MMSteppingAction() : G4UserSteppingAction(), m_steps()
+FW::Geant4::MMSteppingAction::MMSteppingAction()
+  : G4UserSteppingAction(), m_steps()
 // m_volMgr(MaterialRunAction::Instance()->getGeant4VolumeManager())
 {
   if (fgInstance) {
@@ -31,13 +33,13 @@ FW::G4::MMSteppingAction::MMSteppingAction() : G4UserSteppingAction(), m_steps()
   }
 }
 
-FW::G4::MMSteppingAction::~MMSteppingAction()
+FW::Geant4::MMSteppingAction::~MMSteppingAction()
 {
   fgInstance = nullptr;
 }
 
 void
-FW::G4::MMSteppingAction::UserSteppingAction(const G4Step* step)
+FW::Geant4::MMSteppingAction::UserSteppingAction(const G4Step* step)
 {
   // get the material
   G4Material* material = step->GetPreStepPoint()->GetMaterial();
@@ -78,16 +80,17 @@ FW::G4::MMSteppingAction::UserSteppingAction(const G4Step* step)
        G4cout << "steplength: " << steplength << G4endl;*/
 
     // create the RecordedMaterialProperties
-    const auto&          rawPos = step->GetPreStepPoint()->GetPosition();
-    const Acts::Vector3D pos(rawPos.x(), rawPos.y(), rawPos.z());
-    const Acts::MaterialProperties matprop(X0, L0, A, Z, rho, steplength);
-    const Acts::RecordedMaterialProperties recMatProp(matprop, pos);
-    m_steps.push_back(recMatProp);
+    const auto&               rawPos = step->GetPreStepPoint()->GetPosition();
+    Acts::MaterialInteraction mInteraction;
+    mInteraction.position = Acts::Vector3D(rawPos.x(), rawPos.y(), rawPos.z());
+    mInteraction.materialProperties
+        = Acts::MaterialProperties(X0, L0, A, Z, rho, steplength);
+    m_steps.push_back(mInteraction);
   }
 }
 
 void
-FW::G4::MMSteppingAction::Reset()
+FW::Geant4::MMSteppingAction::Reset()
 {
   m_steps.clear();
 }
diff --git a/Plugins/Json/CMakeLists.txt b/Plugins/Json/CMakeLists.txt
index 77020c27aa28e96644f116e803ffca0aba7b5c8d..a231045b4c78c982ca1642b441888daa41493989 100644
--- a/Plugins/Json/CMakeLists.txt
+++ b/Plugins/Json/CMakeLists.txt
@@ -1,3 +1,10 @@
-add_library(ACTFWJsonPlugin INTERFACE)
-target_include_directories(ACTFWJsonPlugin INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/> $<INSTALL_INTERFACE:include>)
+set(srcs src/JsonMaterialWriter.cpp
+         src/JsonGeometryConverter.cpp)
+
+add_library(ACTFWJsonPlugin SHARED ${srcs})
+target_include_directories(ACTFWJsonPlugin PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
+target_link_libraries(ACTFWJsonPlugin PUBLIC ActsCore ActsJsonPlugin) 
+target_link_libraries(ACTFWJsonPlugin PUBLIC ACTFramework)
+
+install(TARGETS ACTFWJsonPlugin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
 install(DIRECTORY include/ACTFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
diff --git a/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp b/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..998a302c665ce865915e7b1a0df1d06ae5d01dcb
--- /dev/null
+++ b/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp
@@ -0,0 +1,236 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 <map>
+#include "Acts/Detector/TrackingGeometry.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
+#include "Acts/Material/MaterialProperties.hpp"
+#include "Acts/Plugins/Json/lib/json.hpp"
+#include "Acts/Utilities/BinUtility.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/Logger.hpp"
+
+// Convenience shorthand
+using json = nlohmann::json;
+
+namespace Acts {
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+
+using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
+}
+
+namespace FW {
+
+namespace Json {
+
+  using SurfaceMaterialRep
+      = std::map<geo_id_value, const Acts::ISurfaceMaterial*>;
+  using VolumeMaterialRep
+      = std::map<geo_id_value, const Acts::IVolumeMaterial*>;
+
+  /// @brief Layer representation for Json writing
+  struct LayerRep
+  {
+    // the layer id
+    Acts::GeometryID layerID;
+
+    SurfaceMaterialRep            sensitives;
+    SurfaceMaterialRep            approaches;
+    const Acts::ISurfaceMaterial* representing = nullptr;
+
+    /// The LayerRep is actually worth it to write out
+    operator bool() const
+    {
+      return (sensitives.size() != 0 or approaches.size() != 0
+              or representing != nullptr);
+    }
+  };
+
+  /// @brief Volume representation for Json writing
+  struct VolumeRep
+  {
+    // the geometry id
+    Acts::GeometryID volumeID;
+
+    /// the namne
+    std::string volumeName;
+
+    std::map<geo_id_value, LayerRep> layers;
+    SurfaceMaterialRep           boundaries;
+    const Acts::IVolumeMaterial* material = nullptr;
+
+    /// The VolumeRep is actually worth it to write out
+    operator bool() const
+    {
+      return (layers.size() != 0 or boundaries.size() != 0
+              or material != nullptr);
+    }
+  };
+
+  /// @brief Detector representation for Json writing
+  struct DetectorRep
+  {
+
+    std::map<geo_id_value, VolumeRep> volumes;
+  };
+
+  /// @class JsonGeometryConverter
+  ///
+  /// @brief read the material from Json
+  class JsonGeometryConverter
+  {
+
+  public:
+    /// @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 type key -> proto, else
+      std::string typekey = "type";
+      /// The data key
+      std::string datakey = "data";
+      /// The default logger
+      std::shared_ptr<const Acts::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;
+      /// 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 = "JsonGeometryConverter",
+             Acts::Logging::Level lvl   = Acts::Logging::INFO)
+        : logger(Acts::getDefaultLogger(lname, lvl)), name(lname)
+      {
+      }
+    };
+
+    /// Constructor
+    ///
+    /// @param cfg configuration struct for the reader
+    JsonGeometryConverter(const Config& cfg);
+
+    /// Destructor
+    ~JsonGeometryConverter() = default;
+
+    /// Convert method
+    ///
+    /// @param surfaceMaterialMap The indexed material map collection
+    std::pair<Acts::SurfaceMaterialMap, Acts::VolumeMaterialMap>
+    jsonToMaterialMaps(const json& materialmaps);
+
+    /// Convert method
+    ///
+    /// @param surfaceMaterialMap The indexed material map collection
+    json
+    materialMapsToJson(const Acts::DetectorMaterialMaps& maps);
+
+    /// Write method
+    ///
+    /// @param tGeometry is the tracking geometry which contains the material
+    json
+    trackingGeometryToJson(const Acts::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 Acts::TrackingVolume& tVolume);
+
+    /// Convert to internal representation method
+    ///
+    /// @param tGeometry is the tracking geometry which contains the material
+    LayerRep
+    convertToRep(const Acts::Layer& tLayer);
+
+    /// Create the Surface Material from Json
+    /// - factory method, ownership given
+    /// @param material is the json part representing a material object
+    const Acts::ISurfaceMaterial*
+    jsonToSurfaceMaterial(const json& material);
+
+    /// Create the Material Matrix from Json
+    ///
+    /// @param data is the json part representing a material data array
+    Acts::MaterialPropertiesMatrix
+    jsonToMaterialMatrix(const json& data);
+
+    /// Create the BinUtility for from Json
+    Acts::BinUtility
+    jsonToBinUtility(const json& bin);
+
+    /// Create Json from a detector represenation
+    json
+    detectorRepToJson(const DetectorRep& detRep);
+
+    /// SurfaceMaterial to Json
+    ///
+    /// @param the SurfaceMaterial
+    json
+    surfaceMaterialToJson(const Acts::ISurfaceMaterial& sMaterial);
+
+    /// The config class
+    Config m_cfg;
+
+    /// Private access to the logging instance
+    const Acts::Logger&
+    logger() const
+    {
+      return *m_cfg.logger;
+    }
+  };
+
+}  // namespace Json
+}  // namespace FW
\ No newline at end of file
diff --git a/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialDecorator.hpp b/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialDecorator.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5cfaa066ed9e126e1187f1c10a3cb2dc9c2c93a7
--- /dev/null
+++ b/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialDecorator.hpp
@@ -0,0 +1,106 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 <fstream>
+#include <map>
+#include <mutex>
+#include "ACTFW/Plugins/Json/JsonGeometryConverter.hpp"
+#include "Acts/Detector/TrackingVolume.hpp"
+#include "Acts/Material/IMaterialDecorator.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
+#include "Acts/Surfaces/Surface.hpp"
+
+// Convenience shorthand
+using json = nlohmann::json;
+
+namespace Acts {
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+}
+
+namespace FW {
+
+namespace Json {
+
+  /// @brief Material decorator from Json format
+  ///
+  /// This reads in material maps for surfaces and volumes
+  /// from a json file
+  class JsonMaterialDecorator : public Acts::IMaterialDecorator
+  {
+  public:
+    JsonMaterialDecorator(const JsonGeometryConverter::Config& rConfig,
+                          const std::string&                   jFileName,
+                          bool clearSurfaceMaterial = true,
+                          bool clearVolumeMaterial  = true)
+      : m_readerConfig(rConfig)
+      , m_clearSurfaceMaterial(clearSurfaceMaterial)
+      , m_clearVolumeMaterial(clearVolumeMaterial)
+    {
+      // the material reader
+      FW::Json::JsonGeometryConverter::Config jmConverterCfg(
+          "JsonGeometryConverter", Acts::Logging::VERBOSE);
+      FW::Json::JsonGeometryConverter jmConverter(jmConverterCfg);
+
+      std::ifstream ifj(jFileName.c_str());
+      json          jin;
+      ifj >> jin;
+
+      auto maps            = jmConverter.jsonToMaterialMaps(jin);
+      m_surfaceMaterialMap = maps.first;
+      m_volumeMaterialMap  = maps.second;
+    }
+
+    /// Decorate a surface
+    ///
+    /// @param surface the non-cost surface that is decorated
+    void
+    decorate(Acts::Surface& surface) const final
+    {
+      // Clear the material if registered to do so
+      if (m_clearSurfaceMaterial) {
+        surface.assignSurfaceMaterial(nullptr);
+      }
+
+      // Try to find the surface in the map
+      auto sMaterial = m_surfaceMaterialMap.find(surface.geoID());
+      if (sMaterial != m_surfaceMaterialMap.end()) {
+        surface.assignSurfaceMaterial(sMaterial->second);
+      }
+    }
+
+    /// Decorate a TrackingVolume
+    ///
+    /// @param volume the non-cost volume that is decorated
+    void
+    decorate(Acts::TrackingVolume& volume) const final
+    {
+      // Clear the material if registered to do so
+      if (m_clearVolumeMaterial) {
+        volume.assignVolumeMaterial(nullptr);
+      }
+    }
+
+  private:
+    JsonGeometryConverter::Config m_readerConfig;
+    Acts::SurfaceMaterialMap      m_surfaceMaterialMap;
+    Acts::VolumeMaterialMap       m_volumeMaterialMap;
+
+    bool m_clearSurfaceMaterial{true};
+    bool m_clearVolumeMaterial{true};
+  };
+
+}  // namespace Json
+}  // namespace FW
diff --git a/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialWriter.hpp b/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialWriter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0fcbbced9f31d8d92dc6059d7b4d95b59be7347f
--- /dev/null
+++ b/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialWriter.hpp
@@ -0,0 +1,86 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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/.
+
+///////////////////////////////////////////////////////////////////
+// JsonMaterialWriter.h
+///////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include <mutex>
+#include "ACTFW/Framework/ProcessCode.hpp"
+#include "ACTFW/Plugins/Json/JsonGeometryConverter.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+#include "Acts/Utilities/Logger.hpp"
+
+namespace Acts {
+
+class TrackingGeometry;
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+
+using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
+}
+
+namespace FW {
+
+namespace Json {
+
+  /// @class Json Material writer
+  ///
+  /// @brief Writes out Detector material maps
+  /// using the Json Geometry converter
+  class JsonMaterialWriter
+  {
+
+  public:
+    /// Constructor
+    ///
+    /// @param cfg The configuration struct of the converter
+    JsonMaterialWriter(const JsonGeometryConverter::Config& cfg,
+                       const std::string&                   fileName);
+
+    /// Virtual destructor
+    ~JsonMaterialWriter();
+
+    /// Write out the material map
+    ///
+    /// @param detMaterial is the SurfaceMaterial and VolumeMaterial maps
+    void
+    write(const Acts::DetectorMaterialMaps& detMaterial);
+
+    /// Write out the material map from Geometry
+    ///
+    /// @param tGeometry is the TrackingGeometry
+    void
+    write(const Acts::TrackingGeometry& tGeometry);
+
+  private:
+    /// The config class of the converter
+    JsonGeometryConverter::Config m_cfg;
+
+    /// The file name
+    std::string m_fileName;
+
+    /// Private access to the logging instance
+    const Acts::Logger&
+    logger() const
+    {
+      return *m_cfg.logger;
+    }
+  };
+
+}  // namespace Json
+}  // namespace FW
diff --git a/Plugins/Json/src/JsonGeometryConverter.cpp b/Plugins/Json/src/JsonGeometryConverter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ae1f83ab2097597b3331b5fbc68e8796c14a214
--- /dev/null
+++ b/Plugins/Json/src/JsonGeometryConverter.cpp
@@ -0,0 +1,531 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 "ACTFW/Plugins/Json/JsonGeometryConverter.hpp"
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/finder.hpp>
+#include <boost/algorithm/string/iter_find.hpp>
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include "Acts/Detector/TrackingVolume.hpp"
+#include "Acts/Layers/ApproachDescriptor.hpp"
+#include "Acts/Material/BinnedSurfaceMaterial.hpp"
+#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
+#include "Acts/Material/ProtoSurfaceMaterial.hpp"
+#include "Acts/Surfaces/SurfaceArray.hpp"
+#include "Acts/Utilities/BinUtility.hpp"
+#include "Acts/Utilities/BinningType.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+
+FW::Json::JsonGeometryConverter::JsonGeometryConverter(
+    const FW::Json::JsonGeometryConverter::Config& cfg)
+  : m_cfg(std::move(cfg))
+{
+  // Validate the configuration
+  if (!m_cfg.logger) {
+    throw std::invalid_argument("Missing logger");
+  }
+}
+
+std::pair<Acts::SurfaceMaterialMap, Acts::VolumeMaterialMap>
+FW::Json::JsonGeometryConverter::jsonToMaterialMaps(const json& materialmaps)
+{
+
+  auto& j = materialmaps;
+  // The return maps
+  std::pair<Acts::SurfaceMaterialMap, Acts::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::GeometryID volumeID(vid, Acts::GeometryID::volume_mask);
+        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::GeometryID boundaryID(volumeID);
+              boundaryID.add(bid, Acts::GeometryID::boundary_mask);
+              ACTS_VERBOSE("j2a: ---> Found boundary surface " << bid);
+              auto boumat = jsonToSurfaceMaterial(bvalue);
+              maps.first[boundaryID]
+                  = std::shared_ptr<const Acts::ISurfaceMaterial>(boumat);
+            }
+          } else if (vckey == m_cfg.laykey) {
+            ACTS_VERBOSE("j2a: --> Layer(s) to be parsed");
+            // now loop over layers
+            auto layj = vcvalue;
+            for (auto & [ lkey, lvalue ] : layj.items()) {
+              // create the layer id
+              int              lid = std::stoi(lkey);
+              Acts::GeometryID layerID(volumeID);
+              layerID.add(lid, Acts::GeometryID::layer_mask);
+              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");
+                  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::GeometryID approachID(layerID);
+                    approachID.add(aid, Acts::GeometryID::approach_mask);
+                    ACTS_VERBOSE("j2a: -----> Approach surface " << askey);
+                    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::GeometryID senisitiveID(layerID);
+                    senisitiveID.add(sid, Acts::GeometryID::sensitive_mask);
+                    ACTS_VERBOSE("j2a: -----> Sensitive surface " << sskey);
+                    auto senmat = jsonToSurfaceMaterial(ssvalue);
+                    maps.first[senisitiveID]
+                        = std::shared_ptr<const Acts::ISurfaceMaterial>(senmat);
+                  }
+                }
+              }
+            }
+
+          } else if (vckey == m_cfg.matkey and not vcvalue.empty()) {
+            ACTS_VERBOSE("--> VolumeMaterial to be parsed");
+          }
+        }
+      }
+    } else if (key == m_cfg.geoversion) {
+      ACTS_VERBOSE("Detector version: " << m_cfg.geoversion);
+    }
+  }
+
+  // Return the filled maps
+  return maps;
+}
+
+/// Convert method
+///
+json
+FW::Json::JsonGeometryConverter::materialMapsToJson(
+    const Acts::DetectorMaterialMaps& maps)
+{
+  DetectorRep detRep;
+  // Collect all GeometryIDs per VolumeID for the formatted output
+  for (auto & [ key, value ] : maps.first) {
+    geo_id_value vid    = key.value(Acts::GeometryID::volume_mask);
+    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.value(Acts::GeometryID::layer_mask);
+    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.value(Acts::GeometryID::sensitive_mask);
+      geo_id_value aid = key.value(Acts::GeometryID::approach_mask);
+      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.value(Acts::GeometryID::boundary_mask);
+      volRep->second.boundaries.insert({bid, value.get()});
+    }
+  }
+  for (auto & [ key, value ] : maps.second) {
+    // find the volume representation
+    geo_id_value vid    = key.value(Acts::GeometryID::volume_mask);
+    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
+FW::Json::JsonGeometryConverter::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;
+    // 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;
+        // 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);
+          }
+          // 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);
+          }
+          // 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);
+        }
+        layersj[std::to_string(lkey)] = layj;
+      }
+      volj[m_cfg.laykey] = layersj;
+    }
+
+    volumesj[std::to_string(key)] = volj;
+  }
+
+  detectorj[m_cfg.volkey] = volumesj;
+
+  return detectorj;
+}
+
+/// Create the Surface Material
+const Acts::ISurfaceMaterial*
+FW::Json::JsonGeometryConverter::jsonToSurfaceMaterial(const json& material)
+{
+
+  Acts::ISurfaceMaterial* sMaterial = nullptr;
+  // The bin utility for deescribing the data
+  Acts::BinUtility bUtility;
+  // Convert the material
+  Acts::MaterialPropertiesMatrix 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.size() == 0) {
+    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;
+}
+
+json
+FW::Json::JsonGeometryConverter::trackingGeometryToJson(
+    const Acts::TrackingGeometry& tGeometry)
+{
+  DetectorRep detRep;
+  convertToRep(detRep, *tGeometry.highestTrackingVolume());
+  return detectorRepToJson(detRep);
+}
+
+void
+FW::Json::JsonGeometryConverter::convertToRep(
+    DetectorRep&                detRep,
+    const Acts::TrackingVolume& tVolume)
+{
+  // The writer reader volume representation
+  VolumeRep volRep;
+  // there are confined volumes
+  if (tVolume.confinedVolumes()) {
+    // get through the volumes
+    auto& volumes = tVolume.confinedVolumes()->arrayObjects();
+    // loop over the volumes
+    for (auto& vol : volumes) {
+      // recursive call
+      convertToRep(detRep, *vol);
+    }
+  }
+  // write the material if there's one
+  if (tVolume.volumeMaterial() != nullptr) {
+    volRep.material = tVolume.volumeMaterial();
+  }
+  // there are confied layers
+  if (tVolume.confinedLayers()) {
+    // 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::GeometryID layerID = lay->geoID();
+        geo_id_value     lid     = layerID.value(Acts::GeometryID::layer_mask);
+        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()) {
+      Acts::GeometryID boundaryID = bssfRep.geoID();
+      geo_id_value     bid = boundaryID.value(Acts::GeometryID::boundary_mask);
+      volRep.boundaries[bid] = bssfRep.surfaceMaterial();
+    }
+  }
+  // Write if it's good
+  if (volRep) {
+    Acts::GeometryID volumeID = tVolume.geoID();
+    volRep.volumeName         = tVolume.volumeName();
+    volRep.volumeID           = volumeID;
+    geo_id_value vid          = volumeID.value(Acts::GeometryID::volume_mask);
+    detRep.volumes.insert({vid, std::move(volRep)});
+  }
+  return;
+}
+
+FW::Json::LayerRep
+FW::Json::JsonGeometryConverter::convertToRep(const Acts::Layer& layer)
+{
+  LayerRep layRep;
+  // fill layer ID information
+  layRep.layerID = layer.geoID();
+  if (m_cfg.processSensitives and layer.surfaceArray() != nullptr) {
+    for (auto& ssf : layer.surfaceArray()->surfaces()) {
+      if (ssf != nullptr && ssf->surfaceMaterial()) {
+        Acts::GeometryID sensitiveID = ssf->geoID();
+        geo_id_value sid = sensitiveID.value(Acts::GeometryID::sensitive_mask);
+        layRep.sensitives.insert({sid, ssf->surfaceMaterial()});
+      }
+    }
+  }
+  // the representing
+  if (layer.surfaceRepresentation().surfaceMaterial() != nullptr) {
+    layRep.representing = layer.surfaceRepresentation().surfaceMaterial();
+  }
+  // the approach
+  if (layer.approachDescriptor() != nullptr) {
+    for (auto& asf : layer.approachDescriptor()->containedSurfaces()) {
+      // get the surface and check for material
+      if (asf->surfaceMaterial() != nullptr) {
+        Acts::GeometryID approachID = asf->geoID();
+        geo_id_value aid = approachID.value(Acts::GeometryID::approach_mask);
+        layRep.approaches.insert({aid, asf->surfaceMaterial()});
+      }
+    }
+  }
+  // return the layer representation
+  return layRep;
+}
+
+json
+FW::Json::JsonGeometryConverter::surfaceMaterialToJson(
+    const Acts::ISurfaceMaterial& sMaterial)
+{
+
+  json smj;
+
+  // lemma 0 : accept the surface
+  auto convertMaterialProperties
+      = [](const Acts::MaterialProperties& mp) -> std::vector<float> {
+    // convert when ready
+    if (mp) {
+      /// Return the thickness in mm
+      return {
+          mp.averageX0(),
+          mp.averageL0(),
+          mp.averageZ(),
+          mp.averageA(),
+          mp.averageRho(),
+          mp.thickness(),
+      };
+    }
+    return {};
+  };
+
+  // if a bin utility is 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
+    smj[m_cfg.typekey] = "proto";
+    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";
+      if (m_cfg.writeData) {
+        // write out the data, it's a [[[X0,L0,Z,A,rho,thickness]]]
+        auto& mp = hsMaterial->materialProperties(0, 0);
+        std::vector<std::vector<std::vector<float>>> mmat
+            = {{convertMaterialProperties(mp)}};
+        smj[m_cfg.datakey] = mmat;
+      }
+    } else {
+      // only option remaining: BinnedSurface material
+      // now check if we have a homogeneous material
+      auto bsMaterial
+          = dynamic_cast<const Acts::BinnedSurfaceMaterial*>(&sMaterial);
+      if (bsMaterial != nullptr) {
+        // type is binned
+        smj[m_cfg.typekey] = "binned";
+        bUtility           = &(bsMaterial->binUtility());
+        // convert the data
+        // get the material matrix
+        if (m_cfg.writeData) {
+          auto& mpMatrix = bsMaterial->fullMaterial();
+          std::vector<std::vector<std::vector<float>>> mmat;
+          mmat.reserve(mpMatrix.size());
+          for (auto& mpVector : mpMatrix) {
+            std::vector<std::vector<float>> mvec;
+            mvec.reserve(mpVector.size());
+            for (auto& mp : mpVector) {
+              mvec.push_back(convertMaterialProperties(mp));
+            }
+            mmat.push_back(std::move(mvec));
+          }
+          smj[m_cfg.datakey] = mmat;
+        }
+      }
+    }
+  }
+  // add the bin utility
+  if (bUtility != nullptr) {
+    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());
+      smj[binkeys[ibin]] = binj;
+    }
+  }
+
+  return smj;
+}
+
+/// Create the Material Matrix
+Acts::MaterialPropertiesMatrix
+FW::Json::JsonGeometryConverter::jsonToMaterialMatrix(const json& data)
+{
+  Acts::MaterialPropertiesMatrix mpMatrix;
+  /// This is assumed to be an array or array of array[6]
+  for (auto& outer : data) {
+    Acts::MaterialPropertiesVector mpVector;
+    for (auto& inner : outer) {
+      if (inner.size() > 5) {
+        mpVector.push_back(Acts::MaterialProperties(
+            inner[0], inner[1], inner[2], inner[3], inner[4], inner[5]));
+      } else {
+        mpVector.push_back(Acts::MaterialProperties());
+      }
+    }
+    mpMatrix.push_back(std::move(mpVector));
+  }
+  return mpMatrix;
+}
+
+/// Create the BinUtility for this
+Acts::BinUtility
+FW::Json::JsonGeometryConverter::jsonToBinUtility(const json& bin)
+{
+  // 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];
+  double              min, max = 0;
+  if (bin[3].size() == 2) {
+    min = bin[3][0];
+    max = bin[3][1];
+  }
+  return Acts::BinUtility(bins, min, max, bopt, bval);
+}
diff --git a/Plugins/Json/src/JsonMaterialWriter.cpp b/Plugins/Json/src/JsonMaterialWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f760060d6d2b0bef4f8b45b920eb64209578b80f
--- /dev/null
+++ b/Plugins/Json/src/JsonMaterialWriter.cpp
@@ -0,0 +1,53 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 "ACTFW/Plugins/Json/JsonMaterialWriter.hpp"
+#include <fstream>
+#include <ios>
+#include <iostream>
+#include <stdexcept>
+#include "Acts/Material/BinnedSurfaceMaterial.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+
+FW::Json::JsonMaterialWriter::JsonMaterialWriter(
+    const FW::Json::JsonGeometryConverter::Config& cfg,
+    const std::string&                             fileName)
+  : m_cfg(cfg), m_fileName(fileName)
+{
+  // Validate the configuration
+  if (m_cfg.name.empty()) {
+    throw std::invalid_argument("Missing service name");
+  }
+}
+
+FW::Json::JsonMaterialWriter::~JsonMaterialWriter()
+{
+}
+
+void
+FW::Json::JsonMaterialWriter::write(
+    const Acts::DetectorMaterialMaps& detMaterial)
+{
+  // Evoke the converter
+  FW::Json::JsonGeometryConverter jmConverter(m_cfg);
+  auto jout = jmConverter.materialMapsToJson(detMaterial);
+  // And write the file
+  std::ofstream ofj(m_fileName);
+  ofj << std::setw(4) << jout << std::endl;
+}
+
+void
+FW::Json::JsonMaterialWriter::write(const Acts::TrackingGeometry& tGeometry)
+{
+  // Evoke the converter
+  FW::Json::JsonGeometryConverter jmConverter(m_cfg);
+  auto jout = jmConverter.trackingGeometryToJson(tGeometry);
+  // And write the file
+  std::ofstream ofj(m_fileName);
+  ofj << std::setw(4) << jout << std::endl;
+}
diff --git a/Plugins/Obj/src/ObjTrackingGeometryWriter.cpp b/Plugins/Obj/src/ObjTrackingGeometryWriter.cpp
index 5df6a763b6e1ada45d8f36fcfbbb6d82520a5917..4e17c80670f5c731f911b588e91895ca2d230806 100644
--- a/Plugins/Obj/src/ObjTrackingGeometryWriter.cpp
+++ b/Plugins/Obj/src/ObjTrackingGeometryWriter.cpp
@@ -75,14 +75,14 @@ FW::Obj::ObjTrackingGeometryWriter::write(const AlgorithmContext&     context,
       // layer prefix
       surfaceWriter->write(m_cfg.layerPrefix);
       // try to write the material surface as well
-      if (layer->surfaceRepresentation().associatedMaterial()) {
+      if (layer->surfaceRepresentation().surfaceMaterial()) {
         surfaceWriter->write(context, layer->surfaceRepresentation());
       }
       // the the approaching surfaces and check if they have material
       if (layer->approachDescriptor()) {
         // loop over the contained Surfaces
         for (auto& cSurface : layer->approachDescriptor()->containedSurfaces())
-          if (cSurface->associatedMaterial()) {
+          if (cSurface->surfaceMaterial()) {
             surfaceWriter->write(context, *cSurface);
           }
       }
diff --git a/Plugins/Root/CMakeLists.txt b/Plugins/Root/CMakeLists.txt
index 13b387f52e264fdc60a98cce90208bf8ee45b15f..a5dee1ce40d0d6b121b16591911ee326be6635a3 100644
--- a/Plugins/Root/CMakeLists.txt
+++ b/Plugins/Root/CMakeLists.txt
@@ -1,8 +1,12 @@
-set(sources
-  src/RootParticleWriter.cpp
-  src/RootPlanarClusterWriter.cpp
-  src/RootPropagationStepsWriter.cpp
-  src/RootSimHitWriter.cpp)
+set(sources src/RootMaterialDecorator.cpp
+            src/RootMaterialWriter.cpp            
+            src/RootMaterialTrackReader.cpp
+            src/RootMaterialTrackWriter.cpp
+            src/RootPlanarClusterWriter.cpp
+            src/RootParticleWriter.cpp
+            src/RootPropagationStepsWriter.cpp
+            src/RootSimHitWriter.cpp
+          )
 
 add_library(ACTFWRootPlugin SHARED ${sources})
 target_include_directories(
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootExCellWriter.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootExCellWriter.hpp
deleted file mode 100644
index 535b9c4c50c7b984b868de3717887cbc4b6f26a0..0000000000000000000000000000000000000000
--- a/Plugins/Root/include/ACTFW/Plugins/Root/RootExCellWriter.hpp
+++ /dev/null
@@ -1,130 +0,0 @@
-// This file is part of the Acts project.
-//
-// Copyright (C) 2017-2018 Acts project team
-//
-// 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 <TFile.h>
-#include <TTree.h>
-#include <mutex>
-#include "ACTFW/Framework/IService.hpp"
-#include "ACTFW/Framework/ProcessCode.hpp"
-#include "ACTFW/Framework/WriterT.hpp"
-#include "Acts/Extrapolation/ExtrapolationCell.hpp"
-#include "Acts/Utilities/Logger.hpp"
-
-namespace FW {
-
-namespace Root {
-
-  /// @class ExtrapolationCellWriter
-  ///
-  /// A root based implementation to write out extrapolation steps.
-  /// This is the Legacy equivalent of the PropgationSteps writer.
-  ///
-  /// The event number is part of the written data.
-  ///
-  /// A common file can be provided for to the writer to attach his TTree,
-  /// this is done by setting the Config::rootFile pointer to an existing file
-  ///
-  /// @tparam parameters_t Type of the track parameters
-  ///
-  /// Safe to use from multiple writer threads - uses a std::mutex lock.
-  template <typename parameters_t>
-  class RootExCellWriter
-      : public FW::WriterT<std::vector<Acts::ExtrapolationCell<parameters_t>>>
-  {
-  public:
-    using Base
-        = FW::WriterT<std::vector<Acts::ExtrapolationCell<parameters_t>>>;
-
-    using FW::WriterT<std::vector<Acts::ExtrapolationCell<parameters_t>>>::
-        logger;
-
-    ///  @struct ExtrapolationStep
-    ///  this holds the information to be written out
-    struct ExtrapolationStep
-    {
-      float x, y, z;     ///< position (global)
-      float px, py, pz;  ///< momentum
-      float type;        ///< type of the step
-    };
-
-    /// @brief  The nested config class
-    struct Config
-    {
-    public:
-      std::string collection;             ///< particle collection to write
-      std::string filePath;               ///< path of the output file
-      std::string fileMode = "RECREATE";  ///< file access mode
-      std::string treeName
-          = "extrapolation_cells";       ///< name of the output tree
-      TFile* rootFile       = nullptr;   ///< common root file
-      bool   writeSensitive = true;      ///< indiciation to write out sensitive
-      bool   writeMaterial  = true;      ///< indiciation to write out material
-      bool   writePassive   = true;      ///< indiciation to write out passive
-      bool   writeBoundary  = true;      ///< indiciation to write out boundary
-      unsigned int reservedSteps = 100;  ///< number of steps to be expected
-    };
-
-    /// Constructor
-    /// @param cfg is the configuration class
-    /// @param level The log level of the writer
-    RootExCellWriter(const Config&        cfg,
-                     Acts::Logging::Level level = Acts::Logging::INFO);
-
-    /// Virtual destructor
-    ~RootExCellWriter() override;
-
-    /// End-of-run hook
-    ProcessCode
-    endRun() final override;
-
-  protected:
-    /// The protected writeT method, called by the WriterT base
-    ///
-    /// @tparam parameters_t Type of the parameters object
-    ///
-    /// @param [in] context is the algorithm context for event consistency
-    /// @param [in] ecells are the celss to be written out
-    ProcessCode
-    writeT(const FW::AlgorithmContext&                               context,
-           const std::vector<Acts::ExtrapolationCell<parameters_t>>& ecells)
-        final override;
-
-    Config             m_cfg;         ///< the config class
-    std::mutex         m_writeMutex;  ///< protect multi-threaded writes
-    TFile*             m_outputFile{nullptr};  ///< the output file
-    TTree*             m_outputTree{nullptr};  ///< the output tree
-    int                m_eventNr;              ///< the event number of
-    float              m_eta;                  ///< global eta start
-    float              m_phi;                  ///< global phi start
-    float              m_materialX0;           ///< material in X0
-    float              m_materialL0;           ///< material in L0
-    std::vector<float> m_s_positionX;   ///< global position x of the step
-    std::vector<float> m_s_positionY;   ///< global position y of the step
-    std::vector<float> m_s_positionZ;   ///< global position z of the step
-    std::vector<float> m_s_positionR;   ///< global position z of the step
-    std::vector<float> m_s_materialX0;  ///< step material X0
-    std::vector<float> m_s_materialL0;  ///< step material L0
-    std::vector<int>   m_s_material;    ///< type of the step: material
-    std::vector<int>   m_s_boundary;    ///< type of the step: boundary
-    std::vector<int>   m_s_sensitive;   ///< type of the step: sensitive
-    std::vector<int>   m_s_volumeID;    ///< volume identification
-    std::vector<int>   m_s_layerID;     ///< layer identification
-    std::vector<int>   m_s_surfaceID;   ///< surface identification
-    std::vector<float>
-        m_s_localposition0;  ///< local position - first coordinate
-    std::vector<float>
-        m_s_localposition1;  ///< local position - second coordinate
-    int m_hits;              ///< number of hits in sensitive material
-  };
-
-}  // namespace Root
-}  // namespace FW
-
-#include "RootExCellWriter.ipp"
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootExCellWriter.ipp b/Plugins/Root/include/ACTFW/Plugins/Root/RootExCellWriter.ipp
deleted file mode 100644
index f48611ac47705837d01213475e9efe0975d29f68..0000000000000000000000000000000000000000
--- a/Plugins/Root/include/ACTFW/Plugins/Root/RootExCellWriter.ipp
+++ /dev/null
@@ -1,241 +0,0 @@
-// This file is part of the Acts project.
-//
-// Copyright (C) 2017 Acts project team
-//
-// 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 <ios>
-#include <stdexcept>
-#include "Acts/Utilities/Helpers.hpp"
-
-#include "Acts/Utilities/Helpers.hpp"
-
-template <typename parameters_t>
-FW::ProcessCode
-FW::Root::RootExCellWriter<parameters_t>::writeT(
-    const FW::AlgorithmContext&                               context,
-    const std::vector<Acts::ExtrapolationCell<parameters_t>>& ecells)
-{
-
-  // Exclusive access to the tree while writing
-  std::lock_guard<std::mutex> lock(m_writeMutex);
-  // Get the event number
-  m_eventNr = context.eventNumber;
-
-  const unsigned int reservedSteps = m_cfg.reservedSteps;
-
-  // loop over all the extrapolation cells
-  for (auto& eCell : ecells) {
-    // the event paramters
-    auto sMomentum = eCell.startParameters->momentum();
-    m_eta          = Acts::VectorHelpers::eta(sMomentum);
-    m_phi          = Acts::VectorHelpers::phi(sMomentum);
-    m_materialX0   = eCell.materialX0;
-    m_materialL0   = eCell.materialL0;
-
-    // clear the vectors & reserve
-    // - for main step information
-    m_s_positionX.clear();
-    m_s_positionY.clear();
-    m_s_positionZ.clear();
-    m_s_positionR.clear();
-    m_s_volumeID.clear();
-    m_s_layerID.clear();
-    m_s_surfaceID.clear();
-    m_s_positionX.reserve(reservedSteps);
-    m_s_positionY.reserve(reservedSteps);
-    m_s_positionZ.reserve(reservedSteps);
-    m_s_positionR.reserve(reservedSteps);
-    m_s_volumeID.reserve(reservedSteps);
-    m_s_layerID.reserve(reservedSteps);
-    m_s_surfaceID.reserve(reservedSteps);
-
-    // - for the sensitive
-    if (m_cfg.writeSensitive) {
-      m_s_sensitive.clear();
-      m_s_localposition0.clear();
-      m_s_localposition1.clear();
-      m_s_sensitive.reserve(reservedSteps);
-      m_s_localposition0.reserve(reservedSteps);
-      m_s_localposition1.reserve(reservedSteps);
-    }
-    // - for the material
-    if (m_cfg.writeMaterial) {
-      m_s_material.clear();
-      m_s_materialX0.clear();
-      m_s_materialL0.clear();
-      m_s_material.reserve(reservedSteps);
-      m_s_materialX0.reserve(reservedSteps);
-      m_s_materialL0.reserve(reservedSteps);
-    }
-    // - for the boundary
-    if (m_cfg.writeBoundary) {
-      m_s_boundary.clear();
-      m_s_boundary.reserve(reservedSteps);
-    }
-    // the number of sensitive hits per event
-    m_hits = 0;
-    // loop over extrapolation steps
-    for (auto& es : eCell.extrapolationSteps) {
-      if (es.parameters) {
-        /// step parameters
-        const parameters_t& pars = (*es.parameters);
-        /// type information
-        int material = es.configuration.checkMode(
-            Acts::ExtrapolationMode::CollectMaterial);
-        int boundary = es.configuration.checkMode(
-            Acts::ExtrapolationMode::CollectBoundary);
-        int sensitive = es.configuration.checkMode(
-            Acts::ExtrapolationMode::CollectSensitive);
-        int passive = es.configuration.checkMode(
-            Acts::ExtrapolationMode::CollectPassive);
-
-        /// check the layer, surface, volume ID
-        geo_id_value volumeID = pars.referenceSurface().geoID().value(
-            Acts::GeometryID::volume_mask);
-        geo_id_value layerID = pars.referenceSurface().geoID().value(
-            Acts::GeometryID::layer_mask);
-        geo_id_value surfaceID = pars.referenceSurface().geoID().value(
-            Acts::GeometryID::sensitive_mask);
-        ///
-        if ((m_cfg.writeSensitive && sensitive)
-            || (m_cfg.writeBoundary && boundary)
-            || (m_cfg.writeMaterial && material)
-            || (m_cfg.writePassive && passive)) {
-
-          // the material steps
-          if (m_cfg.writeMaterial) {
-            // the material is being written out
-            double materialStepX0 = 0.;
-            double materialStepL0 = 0.;
-            if (es.material) {
-              // assign the material
-              materialStepX0 = es.materialScaling * es.material.thicknessInX0();
-              materialStepX0 = es.materialScaling * es.material.thicknessInL0();
-            }
-            m_s_materialX0.push_back(materialStepX0);
-            m_s_materialX0.push_back(materialStepL0);
-          }
-
-          /// goblal position information
-          m_s_positionX.push_back(pars.position().x());
-          m_s_positionY.push_back(pars.position().y());
-          m_s_positionZ.push_back(pars.position().z());
-          m_s_positionR.push_back(Acts::VectorHelpers::perp(pars.position()));
-
-          /// local position information - only makes sense for sensitive really
-          if (m_cfg.writeSensitive) {
-            m_s_localposition0.push_back(pars.parameters()[Acts::eLOC_X]);
-            m_s_localposition1.push_back(pars.parameters()[Acts::eLOC_Y]);
-          }
-          /// volume, layer and surface ID
-          m_s_volumeID.push_back(volumeID);
-          m_s_layerID.push_back(layerID);
-          m_s_surfaceID.push_back(surfaceID);
-          /// indicate what hit you have
-          m_s_material.push_back(material);
-          m_s_boundary.push_back(boundary);
-          m_s_sensitive.push_back(sensitive);
-        }
-        if (sensitive) m_hits++;
-      }
-    }
-    m_outputTree->Fill();
-  }
-  // return scuess
-  return FW::ProcessCode::SUCCESS;
-}
-
-template <typename parameters_t>
-FW::Root::RootExCellWriter<parameters_t>::RootExCellWriter(
-    const FW::Root::RootExCellWriter<parameters_t>::Config& cfg,
-    Acts::Logging::Level                                    level)
-  : FW::WriterT<std::vector<Acts::ExtrapolationCell<parameters_t>>>(
-        cfg.collection,
-        "RootExCellWriter",
-        level)
-  , m_cfg(cfg)
-  , m_outputFile(cfg.rootFile)
-{
-  // Validate the configuration
-  if (m_cfg.collection.empty()) {
-    throw std::invalid_argument("Missing input collection");
-  } else if (m_cfg.treeName.empty()) {
-    throw std::invalid_argument("Missing tree name");
-  }
-
-  // Setup ROOT I/O
-  if (m_outputFile == nullptr) {
-    m_outputFile = TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str());
-    if (m_outputFile == nullptr) {
-      throw std::ios_base::failure("Could not open '" + m_cfg.filePath);
-    }
-    m_outputFile->cd();
-  }
-  m_outputTree
-      = new TTree(m_cfg.treeName.c_str(), "TTree from RootPlanarClusterWriter");
-  if (!m_outputTree) throw std::bad_alloc();
-
-  // Event parameters
-  m_outputTree->Branch("event_nr", &m_eventNr);
-
-  // Initial parameters
-  m_outputTree->Branch("eta", &m_eta);
-  m_outputTree->Branch("phi", &m_phi);
-
-  // Output the step information
-  m_outputTree->Branch("step_x", &m_s_positionX);
-  m_outputTree->Branch("step_y", &m_s_positionY);
-  m_outputTree->Branch("step_z", &m_s_positionZ);
-  m_outputTree->Branch("step_r", &m_s_positionR);
-
-  // Identification
-  m_outputTree->Branch("volumeID", &m_s_volumeID);
-  m_outputTree->Branch("layerID", &m_s_layerID);
-  m_outputTree->Branch("surfaceID", &m_s_surfaceID);
-
-  // Material section
-  if (m_cfg.writeMaterial) {
-    m_outputTree->Branch("material_X0", &m_materialX0);
-    m_outputTree->Branch("material_L0", &m_materialL0);
-    m_outputTree->Branch("step_material_X0", &m_s_materialX0);
-    m_outputTree->Branch("step_material_L0", &m_s_materialL0);
-    m_outputTree->Branch("material", &m_s_material);
-  }
-
-  // Sensitive section
-  if (m_cfg.writeSensitive) {
-    m_outputTree->Branch("sensitive", &m_s_sensitive);
-    m_outputTree->Branch("step_l0", &m_s_localposition0);
-    m_outputTree->Branch("step_l1", &m_s_localposition1);
-  }
-
-  // Boundary section
-  if (m_cfg.writeBoundary) m_outputTree->Branch("boundary", &m_s_boundary);
-
-  // Number of sensitive hits
-  m_outputTree->Branch("hits", &m_hits);
-}
-
-template <typename parameters_t>
-FW::Root::RootExCellWriter<parameters_t>::~RootExCellWriter()
-{
-  // Only close the root file that you created yourself
-  if (m_cfg.rootFile == nullptr) {
-    m_outputFile->Close();
-  }
-}
-
-template <typename parameters_t>
-FW::ProcessCode
-FW::Root::RootExCellWriter<parameters_t>::endRun()
-{
-  m_outputFile->cd();
-  m_outputTree->Write();
-  ACTS_VERBOSE("Wrote particles to tree '" << m_cfg.treeName << "' in '"
-                                           << m_cfg.filePath
-                                           << "'");
-  return ProcessCode::SUCCESS;
-}
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialDecorator.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialDecorator.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..695927cc29a4b55c41131250cc75b6bdfb95aa36
--- /dev/null
+++ b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialDecorator.hpp
@@ -0,0 +1,165 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 <map>
+#include <mutex>
+#include "ACTFW/Framework/ProcessCode.hpp"
+#include "Acts/Detector/TrackingVolume.hpp"
+#include "Acts/Material/IMaterialDecorator.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
+#include "Acts/Surfaces/Surface.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+#include "Acts/Utilities/Logger.hpp"
+
+class TFile;
+
+namespace Acts {
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+}
+
+namespace FW {
+
+namespace Root {
+
+  /// @class RootMaterialDecorator
+  ///
+  /// @brief Read the collection of SurfaceMaterial & VolumeMaterial
+  class RootMaterialDecorator : public Acts::IMaterialDecorator
+  {
+  public:
+    /// @class Config
+    /// Configuration of the Reader
+    class Config
+    {
+    public:
+      /// The name of the output tree
+      std::string folderNameBase = "Material";
+      /// The volume identification string
+      std::string voltag = "_vol";
+      /// The layer identification string
+      std::string laytag = "_lay";
+      /// The approach identification string
+      std::string apptag = "_app";
+      /// The sensitive identification string
+      std::string sentag = "_sen";
+      /// The bin number tag
+      std::string ntag = "n";
+      /// The value tag -> binning values: binZ, binR, binPhi, etc.
+      std::string vtag = "v";
+      /// The option tag -> binning options: open, closed
+      std::string otag = "o";
+      /// The range min tag: min value
+      std::string mintag = "min";
+      /// The range max tag: max value
+      std::string maxtag = "max";
+      /// The thickness tag
+      std::string ttag = "t";
+      /// The x0 tag
+      std::string x0tag = "x0";
+      /// The l0 tag
+      std::string l0tag = "l0";
+      /// The A tag
+      std::string atag = "A";
+      /// The Z tag
+      std::string ztag = "Z";
+      /// The rho tag
+      std::string rhotag = "rho";
+      /// The name of the output file
+      std::string fileName = "material-maps.root";
+      /// The default logger
+      std::shared_ptr<const Acts::Logger> logger;
+      // The name of the writer
+      std::string name = "";
+
+      /// Constructor
+      ///
+      /// @param lname Name of the writer tool
+      /// @param lvl The output logging level
+      Config(const std::string&   lname = "MaterialReader",
+             Acts::Logging::Level lvl   = Acts::Logging::INFO)
+        : logger(Acts::getDefaultLogger(lname, lvl)), name(lname)
+      {
+      }
+    };
+
+    /// Constructor
+    ///
+    /// @param cfg configuration struct for the reader
+    RootMaterialDecorator(const Config& cfg);
+
+    /// Destructor
+    ~RootMaterialDecorator();
+
+    /// Decorate a surface
+    ///
+    /// @param surface the non-cost surface that is decorated
+    void
+    decorate(Acts::Surface& surface) const final
+    {
+      // Null out the material for this surface
+      if (m_clearSurfaceMaterial) {
+        surface.assignSurfaceMaterial(nullptr);
+      }
+      // Try to find the surface in the map
+      auto sMaterial = m_surfaceMaterialMap.find(surface.geoID());
+      if (sMaterial != m_surfaceMaterialMap.end()) {
+        surface.assignSurfaceMaterial(sMaterial->second);
+      }
+    }
+
+    /// Decorate a TrackingVolume
+    ///
+    /// @param volume the non-cost volume that is decorated
+    void
+    decorate(Acts::TrackingVolume& volume) const final
+    {
+      // Null out the material for this volume
+      if (m_clearSurfaceMaterial) {
+        volume.assignVolumeMaterial(nullptr);
+      }
+      // Try to find the surface in the map
+      auto vMaterial = m_volumeMaterialMap.find(volume.geoID());
+      if (vMaterial != m_volumeMaterialMap.end()) {
+        volume.assignVolumeMaterial(vMaterial->second);
+      }
+    }
+
+  private:
+    /// The config class
+    Config m_cfg;
+
+    /// The input file
+    TFile* m_inputFile{nullptr};
+
+    /// Surface based material
+    Acts::SurfaceMaterialMap m_surfaceMaterialMap;
+
+    /// Volume based material
+    Acts::VolumeMaterialMap m_volumeMaterialMap;
+
+    bool m_clearSurfaceMaterial{true};
+    bool m_clearVolumeMaterial{true};
+
+    /// Private access to the logging instance
+    const Acts::Logger&
+    logger() const
+    {
+      return *m_cfg.logger;
+    }
+  };
+}  // namespace Root
+}  // namespace FW
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialTrackReader.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialTrackReader.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..079934852e553ad8a4436e93b1f3123fd62e7708
--- /dev/null
+++ b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialTrackReader.hpp
@@ -0,0 +1,151 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 <mutex>
+#include <vector>
+#include "ACTFW/Framework/IReader.hpp"
+#include "ACTFW/Framework/IService.hpp"
+#include "ACTFW/Framework/ProcessCode.hpp"
+#include "Acts/Extrapolator/MaterialInteractor.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/Logger.hpp"
+
+class TChain;
+
+namespace FW {
+
+namespace Root {
+
+  /// @class RootMaterialTrackReader
+  ///
+  /// @brief Reads in MaterialTrack information from a root file
+  /// and fills it into a format to be understood by the MaterialMapping
+  /// algorithm
+  class RootMaterialTrackReader : public IReader
+  {
+  public:
+    /// @brief The nested configuration struct
+    struct Config
+    {
+      std::string collection
+          = "material-tracks";    ///< material collection to read
+      std::string filePath = "";  ///< path of the output file
+      std::string treeName = "material-tracks";  ///< name of the output tree
+      std::vector<std::string> fileList;         ///< The name of the input file
+
+      unsigned int batchSize = 1;  ///!< The number of tracks per event
+
+      /// The default logger
+      std::shared_ptr<const Acts::Logger> logger;
+
+      /// The name of the service
+      std::string name;
+
+      /// Constructor
+      /// @param lname The name of the Material reader
+      /// @parqam lvl The log level for the logger
+      Config(const std::string&   lname = "MaterialReader",
+             Acts::Logging::Level lvl   = Acts::Logging::INFO)
+        : logger(Acts::getDefaultLogger(lname, lvl)), name(lname)
+      {
+      }
+    };
+
+    /// Constructor
+    /// @param cfg The Configuration struct
+    RootMaterialTrackReader(const Config& cfg);
+
+    /// Destructor
+    ~RootMaterialTrackReader();
+
+    /// Framework name() method
+    std::string
+    name() const final override;
+
+    /// Skip a few events in the IO stream
+    /// @param [in] nEvents is the number of skipped events
+    ProcessCode
+    skip(size_t nEvents) final override;
+
+    /// Read out data from the input stream
+    ///
+    /// @param context The algorithm context
+    ProcessCode
+    read(const FW::AlgorithmContext& context) final override;
+
+    /// Return the number of events
+    virtual size_t
+    numEvents() const final override;
+
+  private:
+    /// Private access to the logging instance
+    const Acts::Logger&
+    logger() const
+    {
+      return *m_cfg.logger;
+    }
+
+    /// The config class
+    Config m_cfg;
+
+    /// mutex used to protect multi-threaded reads
+    std::mutex m_read_mutex;
+
+    /// The number of events
+    size_t m_events = 0;
+
+    /// The input tree name
+    TChain* m_inputChain = nullptr;
+
+    float m_v_x;    ///< start global x
+    float m_v_y;    ///< start global y
+    float m_v_z;    ///< start global z
+    float m_v_px;   ///< start global momentum x
+    float m_v_py;   ///< start global momentum y
+    float m_v_pz;   ///< start global momentum z
+    float m_v_phi;  ///< start phi direction
+    float m_v_eta;  ///< start eta direction
+    float m_tX0;    ///< thickness in X0/L0
+    float m_tL0;    ///< thickness in X0/L0
+
+    std::vector<float>* m_step_x = new std::vector<float>;  ///< step x position
+    std::vector<float>* m_step_y = new std::vector<float>;  ///< step y position
+    std::vector<float>* m_step_z = new std::vector<float>;  ///< step z position
+    std::vector<float>* m_step_length
+        = new std::vector<float>;  ///< step length
+    std::vector<float>* m_step_X0
+        = new std::vector<float>;  ///< step material x0
+    std::vector<float>* m_step_L0
+        = new std::vector<float>;  ///< step material l0
+    std::vector<float>* m_step_A = new std::vector<float>;  ///< step material A
+    std::vector<float>* m_step_Z = new std::vector<float>;  ///< step material Z
+    std::vector<float>* m_step_rho
+        = new std::vector<float>;  ///< step material rho
+  };
+
+  inline std::string
+  RootMaterialTrackReader::name() const
+  {
+    return m_cfg.name;
+  }
+
+  inline size_t
+  RootMaterialTrackReader::numEvents() const
+  {
+    return m_events;
+  }
+
+  inline ProcessCode RootMaterialTrackReader::skip(size_t /*nEvents*/)
+  {
+    return ProcessCode::SUCCESS;
+  }
+
+}  // namespace Root
+}  // namespace FW
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a529739c1439f7cb43a906c1bc5f41367f29207a
--- /dev/null
+++ b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp
@@ -0,0 +1,118 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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 <mutex>
+#include "ACTFW/Framework/IService.hpp"
+#include "ACTFW/Framework/ProcessCode.hpp"
+#include "ACTFW/Framework/WriterT.hpp"
+#include "Acts/Extrapolator/MaterialInteractor.hpp"
+#include "Acts/Utilities/Logger.hpp"
+#include "TTree.h"
+
+namespace Acts {
+// Using some short hands for Recorded Material
+using RecordedMaterial = MaterialInteractor::result_type;
+
+// And recorded material track
+// - this is start:  position, start momentum
+//   and the Recorded material
+using RecordedMaterialTrack
+    = std::pair<std::pair<Acts::Vector3D, Acts::Vector3D>, RecordedMaterial>;
+}
+
+namespace FW {
+
+namespace Root {
+
+  /// @class RootMaterialTrackWriter
+  ///
+  /// @brief Writes out MaterialTrack collections from a root file
+  ///
+  /// This service is the root implementation of the IWriterT.
+  /// It writes out a MaterialTrack which is usually generated from
+  /// Geant4 material mapping
+  class RootMaterialTrackWriter
+      : public WriterT<std::vector<Acts::RecordedMaterialTrack>>
+  {
+  public:
+    using Base = WriterT<std::vector<Acts::RecordedMaterialTrack>>;
+
+    /// @brief The nested configuration struct
+    struct Config
+    {
+      std::string collection
+          = "material-tracks";            ///< material collection to write
+      std::string filePath = "";          ///< path of the output file
+      std::string fileMode = "RECREATE";  ///< file access mode
+      std::string treeName = "material-tracks";  ///< name of the output tree
+      TFile*      rootFile = nullptr;            ///< common root file
+
+      /// Re-calculate total values from individual steps (for cross-checks)
+      bool recalculateTotals = false;
+    };
+
+    /// Constructor with
+    /// @param cfg configuration struct
+    /// @param output logging level
+    RootMaterialTrackWriter(const Config&        cfg,
+                            Acts::Logging::Level level = Acts::Logging::INFO);
+
+    /// Virtual destructor
+    ~RootMaterialTrackWriter() override;
+
+    /// Framework intialize method
+    FW::ProcessCode
+    endRun() final override;
+
+  protected:
+    // This implementation holds the actual writing method
+    /// and is called by the WriterT<>::write interface
+    ///
+    /// @param ctx The Algorithm context with per event information
+    /// @param clusters is the data to be written out
+    ProcessCode
+    writeT(const AlgorithmContext&                         ctx,
+           const std::vector<Acts::RecordedMaterialTrack>& materialtracks)
+        final override;
+
+  private:
+    /// The config class
+    Config m_cfg;
+    /// mutex used to protect multi-threaded writes
+    std::mutex m_writeMutex;
+    /// The output file name
+    TFile* m_outputFile;
+    /// The output tree name
+    TTree* m_outputTree;
+
+    float m_v_x;    ///< start global x
+    float m_v_y;    ///< start global y
+    float m_v_z;    ///< start global z
+    float m_v_px;   ///< start global momentum x
+    float m_v_py;   ///< start global momentum y
+    float m_v_pz;   ///< start global momentum z
+    float m_v_phi;  ///< start phi direction
+    float m_v_eta;  ///< start eta direction
+    float m_tX0;    ///< thickness in X0/L0
+    float m_tL0;    ///< thickness in X0/L0
+
+    std::vector<float> m_step_x;       ///< step x position
+    std::vector<float> m_step_y;       ///< step y position
+    std::vector<float> m_step_z;       ///< step z position
+    std::vector<float> m_step_length;  ///< step length
+    std::vector<float> m_step_X0;      ///< step material x0
+    std::vector<float> m_step_L0;      ///< step material l0
+    std::vector<float> m_step_A;       ///< step material A
+    std::vector<float> m_step_Z;       ///< step material Z
+    std::vector<float> m_step_rho;     ///< step material rho
+  };
+
+}  // namespace Root
+}  // namespace FW
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialWriter.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialWriter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..88bd721b3eb5ba85c68b1458ce6dc6c5598be81d
--- /dev/null
+++ b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialWriter.hpp
@@ -0,0 +1,175 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2019 Acts project team
+//
+// 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/.
+
+///////////////////////////////////////////////////////////////////
+// RootMaterialWriter.h
+///////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include <map>
+#include <mutex>
+#include "ACTFW/Framework/ProcessCode.hpp"
+#include "Acts/Detector/TrackingGeometry.hpp"
+#include "Acts/Detector/TrackingVolume.hpp"
+#include "Acts/Material/IMaterialDecorator.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
+#include "Acts/Surfaces/Surface.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+#include "Acts/Utilities/Logger.hpp"
+#include "TFile.h"
+
+namespace Acts {
+
+using SurfaceMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const ISurfaceMaterial>>;
+
+using VolumeMaterialMap
+    = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+
+using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
+}
+
+namespace FW {
+
+namespace Root {
+
+  /// @brief Material decorator from Root format
+  ///
+  /// This reads in material maps for surfaces and volumes
+  /// from a root file
+  class RootMaterialWriter
+  {
+
+  public:
+    /// @class Config
+    ///
+    /// Configuration of the Writer
+    struct Config
+    {
+
+      /// 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;
+
+      /// The name of the output tree
+      std::string folderNameBase = "Material";
+      /// The volume identification string
+      std::string voltag = "_vol";
+      /// The layer identification string
+      std::string laytag = "_lay";
+      /// The approach identification string
+      std::string apptag = "_app";
+      /// The sensitive identification string
+      std::string sentag = "_sen";
+      /// The bin number tag
+      std::string ntag = "n";
+      /// The value tag -> binning values: binZ, binR, binPhi, etc.
+      std::string vtag = "v";
+      /// The option tag -> binning options: open, closed
+      std::string otag = "o";
+      /// The range min tag: min value
+      std::string mintag = "min";
+      /// The range max tag: max value
+      std::string maxtag = "max";
+      /// The thickness tag
+      std::string ttag = "t";
+      /// The x0 tag
+      std::string x0tag = "x0";
+      /// The l0 tag
+      std::string l0tag = "l0";
+      /// The A tag
+      std::string atag = "A";
+      /// The Z tag
+      std::string ztag = "Z";
+      /// The rho tag
+      std::string rhotag = "rho";
+      /// The name of the output file
+      std::string fileName = "material-maps.root";
+      /// The default logger
+      std::shared_ptr<const Acts::Logger> logger;
+      // The name of the writer
+      std::string name = "";
+
+      /// Constructor
+      ///
+      /// @param lname Name of the writer tool
+      /// @param lvl The output logging level
+      Config(const std::string&   lname = "RootMaterialWriter",
+             Acts::Logging::Level lvl   = Acts::Logging::INFO)
+        : logger(Acts::getDefaultLogger(lname, lvl)), name(lname)
+      {
+      }
+    };
+
+    /// Constructor
+    ///
+    /// @param cfg The configuration struct
+    RootMaterialWriter(const Config& cfg);
+
+    /// Virtual destructor
+    ~RootMaterialWriter();
+
+    /// Write out the material map
+    ///
+    /// @param detMaterial is the SurfaceMaterial and VolumeMaterial maps
+    void
+    write(const Acts::DetectorMaterialMaps& detMaterial);
+
+    /// Write out the material map from Geometry
+    ///
+    /// @param tGeometry is the TrackingGeometry
+    void
+    write(const Acts::TrackingGeometry& tGeometry);
+
+  private:
+    /// Collect the material from the tracking geometry
+    ///
+    /// @param tVolume The TrackingVolume for the material to be collected
+    /// @param [in,out] detMatMap the map to be filled
+    void
+    collectMaterial(const Acts::TrackingVolume& tVolume,
+                    Acts::DetectorMaterialMaps& detMatMap);
+
+    /// Collect the material from the tracking geometry
+    ///
+    /// @param tLayer The TrackingVolume for the material to be collected
+    /// @param [in,out] detMatMap the map to be filled
+    void
+    collectMaterial(const Acts::Layer&          tLayer,
+                    Acts::DetectorMaterialMaps& detMatMap);
+
+    /// The config class
+    Config m_cfg;
+
+    /// The output file name
+    TFile* m_outputFile;
+
+    /// Private access to the logging instance
+    const Acts::Logger&
+    logger() const
+    {
+      return *m_cfg.logger;
+    }
+  };
+
+}  // namespace Root
+}  // namespace FW
diff --git a/Plugins/Root/src/RootMaterialDecorator.cpp b/Plugins/Root/src/RootMaterialDecorator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..45cfac91208387ddd1670fd9102ea7d3b96ebcb0
--- /dev/null
+++ b/Plugins/Root/src/RootMaterialDecorator.cpp
@@ -0,0 +1,190 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2018 Acts project team
+//
+// 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 "ACTFW/Plugins/Root/RootMaterialDecorator.hpp"
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/finder.hpp>
+#include <boost/algorithm/string/iter_find.hpp>
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include "Acts/Material/BinnedSurfaceMaterial.hpp"
+#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
+#include "Acts/Utilities/BinUtility.hpp"
+#include "Acts/Utilities/BinningType.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+#include "TFile.h"
+#include "TH2F.h"
+#include "TIterator.h"
+#include "TKey.h"
+#include "TList.h"
+
+FW::Root::RootMaterialDecorator::RootMaterialDecorator(
+    const FW::Root::RootMaterialDecorator::Config& cfg)
+  : m_cfg(cfg), m_inputFile(nullptr)
+{
+  // Validate the configuration
+  if (m_cfg.folderNameBase.empty()) {
+    throw std::invalid_argument("Missing ROOT folder name");
+  } else if (m_cfg.fileName.empty()) {
+    throw std::invalid_argument("Missing file name");
+  } else if (!m_cfg.logger) {
+    throw std::invalid_argument("Missing logger");
+  } else if (m_cfg.name.empty()) {
+    throw std::invalid_argument("Missing service name");
+  }
+
+  // Setup ROOT I/O
+  m_inputFile = TFile::Open(m_cfg.fileName.c_str());
+  if (!m_inputFile) {
+    throw std::ios_base::failure("Could not open '" + m_cfg.fileName);
+  }
+
+  // Get the list of keys from the file
+  TList* tlist = m_inputFile->GetListOfKeys();
+  auto   tIter = tlist->MakeIterator();
+  tIter->Reset();
+
+  // Iterate over the keys in the file
+  while (TKey* key = (TKey*)(tIter->Next())) {
+
+    // The surface material to be read in for this
+    std::shared_ptr<const Acts::ISurfaceMaterial> sMaterial = nullptr;
+
+    // Remember the directory
+    std::string tdName(key->GetName());
+
+    ACTS_VERBOSE("Processing directory: " << tdName);
+
+    // volume
+    std::vector<std::string> splitNames;
+    iter_split(
+        splitNames, tdName, boost::algorithm::first_finder(m_cfg.voltag));
+    boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
+    geo_id_value volID = std::stoi(splitNames[0]);
+    // layer
+    iter_split(
+        splitNames, tdName, boost::algorithm::first_finder(m_cfg.laytag));
+    boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
+    geo_id_value layID = std::stoi(splitNames[0]);
+    // approach
+    iter_split(
+        splitNames, tdName, boost::algorithm::first_finder(m_cfg.apptag));
+    boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
+    geo_id_value appID = std::stoi(splitNames[0]);
+    // sensitive
+    iter_split(
+        splitNames, tdName, boost::algorithm::first_finder(m_cfg.sentag));
+    geo_id_value senID = std::stoi(splitNames[1]);
+
+    // Reconstruct the geometry ID
+    Acts::GeometryID geoID(volID, Acts::GeometryID::volume_mask);
+    geoID.add(layID, Acts::GeometryID::layer_mask);
+    geoID.add(appID, Acts::GeometryID::approach_mask);
+    geoID.add(senID, Acts::GeometryID::sensitive_mask);
+    ACTS_VERBOSE("GeometryID re-constructed as " << geoID.toString());
+
+    // Construct the names
+    std::string nName   = tdName + "/" + m_cfg.ntag;
+    std::string vName   = tdName + "/" + m_cfg.vtag;
+    std::string oName   = tdName + "/" + m_cfg.otag;
+    std::string minName = tdName + "/" + m_cfg.mintag;
+    std::string maxName = tdName + "/" + m_cfg.maxtag;
+    std::string tName   = tdName + "/" + m_cfg.ttag;
+    std::string x0Name  = tdName + "/" + m_cfg.x0tag;
+    std::string l0Name  = tdName + "/" + m_cfg.l0tag;
+    std::string aName   = tdName + "/" + m_cfg.atag;
+    std::string zName   = tdName + "/" + m_cfg.ztag;
+    std::string rhoName = tdName + "/" + m_cfg.rhotag;
+
+    // Get the histograms
+    TH1F* n   = dynamic_cast<TH1F*>(m_inputFile->Get(nName.c_str()));
+    TH1F* v   = dynamic_cast<TH1F*>(m_inputFile->Get(vName.c_str()));
+    TH1F* o   = dynamic_cast<TH1F*>(m_inputFile->Get(oName.c_str()));
+    TH1F* min = dynamic_cast<TH1F*>(m_inputFile->Get(minName.c_str()));
+    TH1F* max = dynamic_cast<TH1F*>(m_inputFile->Get(maxName.c_str()));
+    TH2F* t   = dynamic_cast<TH2F*>(m_inputFile->Get(tName.c_str()));
+    TH2F* x0  = dynamic_cast<TH2F*>(m_inputFile->Get(x0Name.c_str()));
+    TH2F* l0  = dynamic_cast<TH2F*>(m_inputFile->Get(l0Name.c_str()));
+    TH2F* A   = dynamic_cast<TH2F*>(m_inputFile->Get(aName.c_str()));
+    TH2F* Z   = dynamic_cast<TH2F*>(m_inputFile->Get(zName.c_str()));
+    TH2F* rho = dynamic_cast<TH2F*>(m_inputFile->Get(rhoName.c_str()));
+
+    // Only go on when you have all histograms
+    if (n and v and o and min and max and t and x0 and l0 and A and Z and rho) {
+
+      // Get the number of bins
+      int nbins0 = t->GetNbinsX();
+      int nbins1 = t->GetNbinsY();
+
+      // The material matrix
+      Acts::MaterialPropertiesMatrix materialMatrix(
+          nbins1,
+          Acts::MaterialPropertiesVector(nbins0, Acts::MaterialProperties()));
+
+      // We need binned material properties
+      if (nbins0 * nbins1 > 1) {
+        // Fill the matrix first
+        for (int ib0 = 1; ib0 <= nbins0; ++ib0) {
+          for (int ib1 = 1; ib1 <= nbins1; ++ib1) {
+            double dt = t->GetBinContent(ib0, ib1);
+            if (dt > 0.) {
+              double dx0  = x0->GetBinContent(ib0, ib1);
+              double dl0  = l0->GetBinContent(ib0, ib1);
+              double da   = A->GetBinContent(ib0, ib1);
+              double dz   = Z->GetBinContent(ib0, ib1);
+              double drho = rho->GetBinContent(ib0, ib1);
+              // Create material properties
+              materialMatrix[ib1 - 1][ib0 - 1]
+                  = Acts::MaterialProperties(dx0, dl0, da, dz, drho, dt);
+            }
+          }
+        }
+
+        // Now reconstruct the bin untilities
+        Acts::BinUtility bUtility;
+        for (size_t ib = 1; ib < n->GetNbinsX() + 1; ++ib) {
+          size_t              nbins = size_t(n->GetBinContent(ib));
+          Acts::BinningValue  val   = Acts::BinningValue(v->GetBinContent(ib));
+          Acts::BinningOption opt   = Acts::BinningOption(o->GetBinContent(ib));
+          float               rmin  = min->GetBinContent(ib);
+          float               rmax  = max->GetBinContent(ib);
+          bUtility += Acts::BinUtility(nbins, rmin, rmax, opt, val);
+        }
+        ACTS_VERBOSE("Created " << bUtility);
+
+        // Construct the binned material with the right bin utility
+        sMaterial = std::make_shared<const Acts::BinnedSurfaceMaterial>(
+            bUtility, std::move(materialMatrix));
+
+      } else {
+        // Only homogeneous material present
+        double dt   = t->GetBinContent(1, 1);
+        double dx0  = x0->GetBinContent(1, 1);
+        double dl0  = l0->GetBinContent(1, 1);
+        double da   = A->GetBinContent(1, 1);
+        double dz   = Z->GetBinContent(1, 1);
+        double drho = rho->GetBinContent(1, 1);
+        // Create and set the homogenous surface material
+        sMaterial = std::make_shared<const Acts::HomogeneousSurfaceMaterial>(
+            Acts::MaterialProperties(dx0, dl0, da, dz, drho, dt));
+      }
+    }
+    ACTS_VERBOSE("Successfully read Material for : " << geoID.toString());
+
+    // Insert into the new collection
+    m_surfaceMaterialMap.insert({geoID, std::move(sMaterial)});
+  }
+}
+
+FW::Root::RootMaterialDecorator::~RootMaterialDecorator()
+{
+  m_inputFile->Close();
+}
diff --git a/Plugins/Root/src/RootMaterialTrackReader.cpp b/Plugins/Root/src/RootMaterialTrackReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..42d4b157ca8e4281949ba4d005e53bdc77f0f92d
--- /dev/null
+++ b/Plugins/Root/src/RootMaterialTrackReader.cpp
@@ -0,0 +1,126 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2018 Acts project team
+//
+// 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 "ACTFW/Plugins/Root/RootMaterialTrackReader.hpp"
+#include <iostream>
+#include "ACTFW/Framework/WhiteBoard.hpp"
+#include "TChain.h"
+#include "TFile.h"
+
+FW::Root::RootMaterialTrackReader::RootMaterialTrackReader(
+    const FW::Root::RootMaterialTrackReader::Config& cfg)
+  : FW::IReader(), m_cfg(cfg), m_events(0), m_inputChain(nullptr)
+{
+  m_inputChain = new TChain(m_cfg.treeName.c_str());
+
+  // Set the branches
+  m_inputChain->SetBranchAddress("v_x", &m_v_x);
+  m_inputChain->SetBranchAddress("v_y", &m_v_y);
+  m_inputChain->SetBranchAddress("v_z", &m_v_z);
+  m_inputChain->SetBranchAddress("v_px", &m_v_px);
+  m_inputChain->SetBranchAddress("v_py", &m_v_py);
+  m_inputChain->SetBranchAddress("v_pz", &m_v_pz);
+  m_inputChain->SetBranchAddress("v_phi", &m_v_phi);
+  m_inputChain->SetBranchAddress("v_eta", &m_v_eta);
+  m_inputChain->SetBranchAddress("t_X0", &m_tX0);
+  m_inputChain->SetBranchAddress("t_L0", &m_tL0);
+  m_inputChain->SetBranchAddress("mat_x", &m_step_x);
+  m_inputChain->SetBranchAddress("mat_y", &m_step_y);
+  m_inputChain->SetBranchAddress("mat_z", &m_step_z);
+  m_inputChain->SetBranchAddress("mat_step_length", &m_step_length);
+  m_inputChain->SetBranchAddress("mat_X0", &m_step_X0);
+  m_inputChain->SetBranchAddress("mat_L0", &m_step_L0);
+  m_inputChain->SetBranchAddress("mat_A", &m_step_A);
+  m_inputChain->SetBranchAddress("mat_Z", &m_step_Z);
+  m_inputChain->SetBranchAddress("mat_rho", &m_step_rho);
+
+  // loop over the input files
+  for (auto inputFile : m_cfg.fileList) {
+    // add file to the input chain
+    m_inputChain->Add(inputFile.c_str());
+    ACTS_DEBUG("Adding File " << inputFile << " to tree '" << m_cfg.treeName
+                              << "'.");
+  }
+
+  m_events = m_inputChain->GetEntries();
+  ACTS_DEBUG("The full chain has " << m_events << " entries.");
+}
+
+FW::Root::RootMaterialTrackReader::~RootMaterialTrackReader()
+{
+
+  delete m_step_x;
+  delete m_step_y;
+  delete m_step_z;
+  delete m_step_length;
+  delete m_step_X0;
+  delete m_step_L0;
+  delete m_step_A;
+  delete m_step_Z;
+  delete m_step_rho;
+}
+
+FW::ProcessCode
+FW::Root::RootMaterialTrackReader::read(const FW::AlgorithmContext& context)
+{
+
+  ACTS_DEBUG("Trying to read recorded material from tracks.");
+  // read in the material track
+  if (m_inputChain && context.eventNumber < m_events) {
+    // lock the mutex
+    std::lock_guard<std::mutex> lock(m_read_mutex);
+    // now read
+
+    // The collection to be written
+    std::vector<Acts::RecordedMaterialTrack> mtrackCollection;
+
+    for (size_t ib = 0; ib < m_cfg.batchSize; ++ib) {
+
+      // Read the correct entry: batch size * event_number + ib
+      m_inputChain->GetEntry(m_cfg.batchSize * context.eventNumber + ib);
+      ACTS_VERBOSE("Reading entry: " << m_cfg.batchSize * context.eventNumber
+                       + ib);
+
+      Acts::RecordedMaterialTrack rmTrack;
+      // Fill the position and momentum
+      rmTrack.first.first  = Acts::Vector3D(m_v_x, m_v_y, m_v_z);
+      rmTrack.first.second = Acts::Vector3D(m_v_px, m_v_py, m_v_pz);
+
+      // Fill the individual steps
+      size_t msteps = m_step_length->size();
+      ACTS_VERBOSE("Reading " << msteps << " material steps.");
+      rmTrack.second.materialInteractions.reserve(msteps);
+      rmTrack.second.materialInX0 = 0.;
+      rmTrack.second.materialInL0 = 0.;
+
+      for (size_t is = 0; is < msteps; ++is) {
+
+        double mX0 = (*m_step_X0)[is];
+        double mL0 = (*m_step_L0)[is];
+        double s   = (*m_step_length)[is];
+
+        rmTrack.second.materialInX0 += s / mX0;
+        rmTrack.second.materialInL0 += s / mL0;
+
+        /// Fill the position & the material
+        Acts::MaterialInteraction mInteraction;
+        mInteraction.position
+            = Acts::Vector3D((*m_step_x)[is], (*m_step_y)[is], (*m_step_z)[is]);
+        mInteraction.materialProperties = Acts::MaterialProperties(
+            mX0, mL0, (*m_step_A)[is], (*m_step_Z)[is], (*m_step_rho)[is], s);
+        rmTrack.second.materialInteractions.push_back(std::move(mInteraction));
+      }
+      mtrackCollection.push_back(std::move(rmTrack));
+    }
+
+    // Write to the collection to the EventStore
+    context.eventStore.add(m_cfg.collection, std::move(mtrackCollection));
+  }
+  // Return success flag
+  return FW::ProcessCode::SUCCESS;
+}
diff --git a/Plugins/Root/src/RootMaterialTrackWriter.cpp b/Plugins/Root/src/RootMaterialTrackWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9de5388dca45cc61190e3eeac1c7d140699e21ea
--- /dev/null
+++ b/Plugins/Root/src/RootMaterialTrackWriter.cpp
@@ -0,0 +1,165 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2018 Acts project team
+//
+// 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 "ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp"
+
+#include <ios>
+#include <iostream>
+#include <stdexcept>
+
+#include "TFile.h"
+
+#include "Acts/Utilities/Helpers.hpp"
+
+using Acts::VectorHelpers::eta;
+using Acts::VectorHelpers::phi;
+using Acts::VectorHelpers::perp;
+
+FW::Root::RootMaterialTrackWriter::RootMaterialTrackWriter(
+    const FW::Root::RootMaterialTrackWriter::Config& cfg,
+    Acts::Logging::Level                             level)
+  : Base(cfg.collection, "RootMaterialTrackWriter", level)
+  , m_cfg(cfg)
+  , m_outputFile(cfg.rootFile)
+{
+  // An input collection name and tree name must be specified
+  if (m_cfg.collection.empty()) {
+    throw std::invalid_argument("Missing input collection");
+  } else if (m_cfg.treeName.empty()) {
+    throw std::invalid_argument("Missing tree name");
+  }
+
+  // Setup ROOT I/O
+  if (m_outputFile == nullptr) {
+    m_outputFile = TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str());
+    if (m_outputFile == nullptr) {
+      throw std::ios_base::failure("Could not open '" + m_cfg.filePath);
+    }
+  }
+  m_outputFile->cd();
+  m_outputTree
+      = new TTree(m_cfg.treeName.c_str(), "TTree from RootMaterialTrackWriter");
+  if (m_outputTree == nullptr) throw std::bad_alloc();
+
+  // Set the branches
+  m_outputTree->Branch("v_x", &m_v_x);
+  m_outputTree->Branch("v_y", &m_v_y);
+  m_outputTree->Branch("v_z", &m_v_z);
+  m_outputTree->Branch("v_px", &m_v_px);
+  m_outputTree->Branch("v_py", &m_v_py);
+  m_outputTree->Branch("v_pz", &m_v_pz);
+  m_outputTree->Branch("v_phi", &m_v_phi);
+  m_outputTree->Branch("v_eta", &m_v_eta);
+  m_outputTree->Branch("t_X0", &m_tX0);
+  m_outputTree->Branch("t_L0", &m_tL0);
+  m_outputTree->Branch("mat_x", &m_step_x);
+  m_outputTree->Branch("mat_y", &m_step_y);
+  m_outputTree->Branch("mat_z", &m_step_z);
+  m_outputTree->Branch("mat_step_length", &m_step_length);
+  m_outputTree->Branch("mat_X0", &m_step_X0);
+  m_outputTree->Branch("mat_L0", &m_step_L0);
+  m_outputTree->Branch("mat_A", &m_step_A);
+  m_outputTree->Branch("mat_Z", &m_step_Z);
+  m_outputTree->Branch("mat_rho", &m_step_rho);
+}
+
+FW::Root::RootMaterialTrackWriter::~RootMaterialTrackWriter()
+{
+  m_outputFile->Close();
+}
+
+FW::ProcessCode
+FW::Root::RootMaterialTrackWriter::endRun()
+{
+  // write the tree and close the file
+  ACTS_INFO("Writing ROOT output File : " << m_cfg.filePath);
+  m_outputFile->cd();
+  m_outputTree->Write();
+  return FW::ProcessCode::SUCCESS;
+}
+
+FW::ProcessCode
+FW::Root::RootMaterialTrackWriter::writeT(
+    const AlgorithmContext&                         ctx,
+    const std::vector<Acts::RecordedMaterialTrack>& materialTracks)
+{
+  // Exclusive access to the tree while writing
+  std::lock_guard<std::mutex> lock(m_writeMutex);
+
+  // loop over the material tracks and write them out
+  for (auto& mtrack : materialTracks) {
+
+    // clearing the vector first
+    m_step_x.clear();
+    m_step_y.clear();
+    m_step_z.clear();
+    m_step_length.clear();
+    m_step_X0.clear();
+    m_step_L0.clear();
+    m_step_A.clear();
+    m_step_Z.clear();
+    m_step_rho.clear();
+
+    // reserve the vector then
+    size_t mints = mtrack.second.materialInteractions.size();
+    m_step_x.reserve(mints);
+    m_step_y.reserve(mints);
+    m_step_z.reserve(mints);
+    m_step_length.reserve(mints);
+    m_step_X0.reserve(mints);
+    m_step_L0.reserve(mints);
+    m_step_A.reserve(mints);
+    m_step_Z.reserve(mints);
+    m_step_rho.reserve(mints);
+
+    // reset the global counter
+    if (m_cfg.recalculateTotals) {
+      m_tX0 = 0.;
+      m_tL0 = 0.;
+    } else {
+      m_tX0 = mtrack.second.materialInX0;
+      m_tL0 = mtrack.second.materialInL0;
+    }
+
+    // set the track information at vertex
+    m_v_x   = mtrack.first.first.x();
+    m_v_y   = mtrack.first.first.y();
+    m_v_z   = mtrack.first.first.z();
+    m_v_px  = mtrack.first.second.x();
+    m_v_py  = mtrack.first.second.y();
+    m_v_pz  = mtrack.first.second.z();
+    m_v_phi = phi(mtrack.first.second);
+    m_v_eta = eta(mtrack.first.second);
+
+    // an now loop over the material
+    for (auto& mint : mtrack.second.materialInteractions) {
+      // the material step position information
+      m_step_x.push_back(mint.position.x());
+      m_step_y.push_back(mint.position.y());
+      m_step_z.push_back(mint.position.z());
+      // the material information
+      const auto& mprops = mint.materialProperties;
+      m_step_length.push_back(mprops.thickness());
+      m_step_X0.push_back(mprops.averageX0());
+      m_step_L0.push_back(mprops.averageL0());
+      m_step_A.push_back(mprops.averageA());
+      m_step_Z.push_back(mprops.averageZ());
+      m_step_rho.push_back(mprops.averageRho());
+      // re-calculate if defined to do so
+      if (m_cfg.recalculateTotals) {
+        m_tX0 += mprops.thicknessInX0();
+        m_tL0 += mprops.thicknessInL0();
+      }
+    }
+    // write to
+    m_outputTree->Fill();
+  }
+
+  // return success
+  return FW::ProcessCode::SUCCESS;
+}
diff --git a/Plugins/Root/src/RootMaterialWriter.cpp b/Plugins/Root/src/RootMaterialWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a00523d42d6b373e07ddc42efa2aaebd7ea5bf51
--- /dev/null
+++ b/Plugins/Root/src/RootMaterialWriter.cpp
@@ -0,0 +1,296 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2017-2018 Acts project team
+//
+// 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 "ACTFW/Plugins/Root/RootMaterialWriter.hpp"
+#include <ios>
+#include <iostream>
+#include <stdexcept>
+#include "Acts/Material/BinnedSurfaceMaterial.hpp"
+#include "Acts/Utilities/GeometryID.hpp"
+#include "TFile.h"
+#include "TH2F.h"
+
+FW::Root::RootMaterialWriter::RootMaterialWriter(
+    const FW::Root::RootMaterialWriter::Config& cfg)
+  : m_cfg(cfg), m_outputFile(nullptr)
+{
+  // Validate the configuration
+  if (m_cfg.folderNameBase.empty()) {
+    throw std::invalid_argument("Missing folder name base");
+  } else if (m_cfg.fileName.empty()) {
+    throw std::invalid_argument("Missing file name");
+  } else if (!m_cfg.logger) {
+    throw std::invalid_argument("Missing logger");
+  } else if (m_cfg.name.empty()) {
+    throw std::invalid_argument("Missing service name");
+  }
+
+  // Setup ROOT I/O
+  m_outputFile = TFile::Open(m_cfg.fileName.c_str(), "recreate");
+  if (!m_outputFile) {
+    throw std::ios_base::failure("Could not open '" + m_cfg.fileName);
+  }
+}
+
+FW::Root::RootMaterialWriter::~RootMaterialWriter()
+{
+  m_outputFile->Close();
+}
+
+void
+FW::Root::RootMaterialWriter::write(
+    const Acts::DetectorMaterialMaps& detMaterial)
+{
+
+  // Change to the output file
+  m_outputFile->cd();
+
+  auto& surfaceMaps = detMaterial.first;
+  for (auto & [ key, value ] : surfaceMaps) {
+
+    // Get the Surface material
+    const Acts::ISurfaceMaterial* sMaterial = value.get();
+
+    // get the geometry ID
+    Acts::GeometryID geoID = key;
+    // decode the geometryID
+    geo_id_value gvolID = geoID.value(Acts::GeometryID::volume_mask);
+    geo_id_value glayID = geoID.value(Acts::GeometryID::layer_mask);
+    geo_id_value gappID = geoID.value(Acts::GeometryID::approach_mask);
+    geo_id_value gsenID = geoID.value(Acts::GeometryID::sensitive_mask);
+    // create the directory
+    std::string tdName = m_cfg.folderNameBase.c_str();
+    tdName += m_cfg.voltag + std::to_string(gvolID);
+    tdName += m_cfg.laytag + std::to_string(glayID);
+    tdName += m_cfg.apptag + std::to_string(gappID);
+    tdName += m_cfg.sentag + std::to_string(gsenID);
+    // create a new directory
+    m_outputFile->mkdir(tdName.c_str());
+    m_outputFile->cd(tdName.c_str());
+
+    ACTS_VERBOSE("Writing out map at " << tdName);
+
+    size_t bins0 = 1, bins1 = 1;
+    // understand what sort of material you have in mind
+    const Acts::BinnedSurfaceMaterial* bsm
+        = dynamic_cast<const Acts::BinnedSurfaceMaterial*>(sMaterial);
+    if (bsm) {
+      // overwrite the bin numbers
+      bins0 = bsm->binUtility().bins(0);
+      bins1 = bsm->binUtility().bins(1);
+
+      // Get the binning data
+      auto& binningData = bsm->binUtility().binningData();
+      // 1-D or 2-D maps
+      size_t binningBins = binningData.size();
+
+      // The bin number information
+      TH1F* n = new TH1F(m_cfg.ntag.c_str(),
+                         "bins; bin",
+                         binningBins,
+                         -0.5,
+                         binningBins - 0.5);
+
+      // The binning value information
+      TH1F* v = new TH1F(m_cfg.vtag.c_str(),
+                         "binning values; bin",
+                         binningBins,
+                         -0.5,
+                         binningBins - 0.5);
+
+      // The binning option information
+      TH1F* o = new TH1F(m_cfg.otag.c_str(),
+                         "binning options; bin",
+                         binningBins,
+                         -0.5,
+                         binningBins - 0.5);
+
+      // The binning option information
+      TH1F* min = new TH1F(m_cfg.mintag.c_str(),
+                           "min; bin",
+                           binningBins,
+                           -0.5,
+                           binningBins - 0.5);
+
+      // The binning option information
+      TH1F* max = new TH1F(m_cfg.maxtag.c_str(),
+                           "max; bin",
+                           binningBins,
+                           -0.5,
+                           binningBins - 0.5);
+
+      // Now fill the histogram content
+      size_t b = 1;
+      for (auto bData : binningData) {
+        // Fill: nbins, value, option, min, max
+        n->SetBinContent(b, int(binningData[b - 1].bins()));
+        v->SetBinContent(b, int(binningData[b - 1].binvalue));
+        o->SetBinContent(b, int(binningData[b - 1].option));
+        min->SetBinContent(b, binningData[b - 1].min);
+        max->SetBinContent(b, binningData[b - 1].max);
+        ++b;
+      }
+      n->Write();
+      v->Write();
+      o->Write();
+      min->Write();
+      max->Write();
+    }
+
+    TH2F* t = new TH2F(m_cfg.ttag.c_str(),
+                       "thickness [mm] ;b0 ;b1",
+                       bins0,
+                       -0.5,
+                       bins0 - 0.5,
+                       bins1,
+                       -0.5,
+                       bins1 - 0.5);
+    TH2F* x0 = new TH2F(m_cfg.x0tag.c_str(),
+                        "X_{0} [mm] ;b0 ;b1",
+                        bins0,
+                        -0.5,
+                        bins0 - 0.5,
+                        bins1,
+                        -0.5,
+                        bins1 - 0.5);
+    TH2F* l0 = new TH2F(m_cfg.l0tag.c_str(),
+                        "#Lambda_{0} [mm] ;b0 ;b1",
+                        bins0,
+                        -0.5,
+                        bins0 - 0.5,
+                        bins1,
+                        -0.5,
+                        bins1 - 0.5);
+    TH2F* A = new TH2F(m_cfg.atag.c_str(),
+                       "X_{0} [mm] ;b0 ;b1",
+                       bins0,
+                       -0.5,
+                       bins0 - 0.5,
+                       bins1,
+                       -0.5,
+                       bins1 - 0.5);
+    TH2F* Z = new TH2F(m_cfg.ztag.c_str(),
+                       "#Lambda_{0} [mm] ;b0 ;b1",
+                       bins0,
+                       -0.5,
+                       bins0 - 0.5,
+                       bins1,
+                       -0.5,
+                       bins1 - 0.5);
+    TH2F* rho = new TH2F(m_cfg.rhotag.c_str(),
+                         "#rho [g/mm^3] ;b0 ;b1",
+                         bins0,
+                         -0.5,
+                         bins0 - 0.5,
+                         bins1,
+                         -0.5,
+                         bins1 - 0.5);
+
+    // loop over the material and fill
+    for (size_t b0 = 0; b0 < bins0; ++b0) {
+      for (size_t b1 = 0; b1 < bins1; ++b1) {
+        // get the material for the bin
+        auto& mat = sMaterial->materialProperties(b0, b1);
+        if (mat) {
+          t->SetBinContent(b0 + 1, b1 + 1, mat.thickness());
+          x0->SetBinContent(b0 + 1, b1 + 1, mat.material().X0());
+          l0->SetBinContent(b0 + 1, b1 + 1, mat.material().L0());
+          A->SetBinContent(b0 + 1, b1 + 1, mat.material().A());
+          Z->SetBinContent(b0 + 1, b1 + 1, mat.material().Z());
+          rho->SetBinContent(b0 + 1, b1 + 1, mat.material().rho());
+        }
+      }
+    }
+    t->Write();
+    x0->Write();
+    l0->Write();
+    A->Write();
+    Z->Write();
+    rho->Write();
+  }
+}
+
+void
+FW::Root::RootMaterialWriter::write(const Acts::TrackingGeometry& tGeometry)
+{
+  // Create a detector material map and loop recursively through it
+  Acts::DetectorMaterialMaps detMatMap;
+  auto                       hVolume = tGeometry.highestTrackingVolume();
+  if (hVolume != nullptr) {
+    collectMaterial(*hVolume, detMatMap);
+  }
+  // Write the resulting map to the file
+  write(detMatMap);
+}
+
+void
+FW::Root::RootMaterialWriter::collectMaterial(
+    const Acts::TrackingVolume& tVolume,
+    Acts::DetectorMaterialMaps& detMatMap)
+{
+
+  // If the volume has volume material, write that
+  if (tVolume.volumeMaterialPtr() != nullptr and m_cfg.processVolumes) {
+    detMatMap.second[tVolume.geoID()] = tVolume.volumeMaterialPtr();
+  }
+
+  // If confined layers exist, loop over them and collect the layer material
+  if (tVolume.confinedLayers() != nullptr) {
+    for (auto& lay : tVolume.confinedLayers()->arrayObjects()) {
+      collectMaterial(*lay, detMatMap);
+    }
+  }
+
+  // If any of the boundary surfaces has material collect that
+  if (m_cfg.processBoundaries) {
+    for (auto& bou : tVolume.boundarySurfaces()) {
+      const auto& bSurface = bou->surfaceRepresentation();
+      if (bSurface.surfaceMaterialPtr() != nullptr) {
+        detMatMap.first[bSurface.geoID()] = bSurface.surfaceMaterialPtr();
+      }
+    }
+  }
+
+  // If the volume has sub volumes, step down
+  if (tVolume.confinedVolumes() != nullptr) {
+    for (auto& tvol : tVolume.confinedVolumes()->arrayObjects()) {
+      collectMaterial(*tvol, detMatMap);
+    }
+  }
+}
+
+void
+FW::Root::RootMaterialWriter::collectMaterial(
+    const Acts::Layer&          tLayer,
+    Acts::DetectorMaterialMaps& detMatMap)
+{
+  // If the representing surface has material, collect it
+  const auto& rSurface = tLayer.surfaceRepresentation();
+  if (rSurface.surfaceMaterialPtr() != nullptr and m_cfg.processRepresenting) {
+    detMatMap.first[rSurface.geoID()] = rSurface.surfaceMaterialPtr();
+  }
+
+  // Check the approach surfaces
+  if (tLayer.approachDescriptor() != nullptr and m_cfg.processApproaches) {
+    for (auto& aSurface : tLayer.approachDescriptor()->containedSurfaces()) {
+      if (aSurface->surfaceMaterialPtr() != nullptr) {
+        detMatMap.first[aSurface->geoID()] = aSurface->surfaceMaterialPtr();
+      }
+    }
+  }
+
+  // Check the sensitive surfaces
+  if (tLayer.surfaceArray() != nullptr and m_cfg.processSensitives) {
+    // sensitive surface loop
+    for (auto& sSurface : tLayer.surfaceArray()->surfaces()) {
+      if (sSurface->surfaceMaterialPtr() != nullptr) {
+        detMatMap.first[sSurface->geoID()] = sSurface->surfaceMaterialPtr();
+      }
+    }
+  }
+}
diff --git a/external/acts-core b/external/acts-core
index e0ca76b4c611b77cf9f3c92a1825da25e516aca4..19d57d9646a3c5ad89a55ed7f6a8fe355e77d63a 160000
--- a/external/acts-core
+++ b/external/acts-core
@@ -1 +1 @@
-Subproject commit e0ca76b4c611b77cf9f3c92a1825da25e516aca4
+Subproject commit 19d57d9646a3c5ad89a55ed7f6a8fe355e77d63a
diff --git a/external/acts-fatras b/external/acts-fatras
index 167f6ba9be0f426e13530b086997f7f8fde0f8cf..826fd8dd88e50472947acf7184519582e13b9d7c 160000
--- a/external/acts-fatras
+++ b/external/acts-fatras
@@ -1 +1 @@
-Subproject commit 167f6ba9be0f426e13530b086997f7f8fde0f8cf
+Subproject commit 826fd8dd88e50472947acf7184519582e13b9d7c