diff --git a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp
index 78fcdec1538b4117f837f8d90a1ce66e54d6b587..0af807ed4312d65e63f79f8036633677e9711e8b 100644
--- a/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp
+++ b/Algorithms/MaterialMapping/include/ACTFW/MaterialMapping/MaterialMapping.hpp
@@ -24,8 +24,14 @@
 
 namespace Acts {
 class TrackingGeometry;
-using IndexedSurfaceMaterial
-    = std::pair<GeometryID, std::unique_ptr<const ISurfaceMaterial>>;
+
+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 {
@@ -67,8 +73,8 @@ public:
     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<FW::IWriterT<Acts::DetectorMaterialMaps>>>
+        materialWriters;
 
     /// The TrackingGeometry to be mapped on
     std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry = nullptr;
diff --git a/Algorithms/MaterialMapping/src/MaterialMapping.cpp b/Algorithms/MaterialMapping/src/MaterialMapping.cpp
index 512f333bc661a274472de2e947126768558c58bb..c2c1770a555546da5abdff88200795b08643617c 100644
--- a/Algorithms/MaterialMapping/src/MaterialMapping.cpp
+++ b/Algorithms/MaterialMapping/src/MaterialMapping.cpp
@@ -23,8 +23,6 @@ FW::MaterialMapping::MaterialMapping(const FW::MaterialMapping::Config& cnf,
 {
   if (!m_cfg.materialMapper) {
     throw std::invalid_argument("Missing material mapper");
-  } 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");
   }
@@ -48,9 +46,15 @@ FW::MaterialMapping::~MaterialMapping()
   writeContext.geoContext      = m_cfg.geoContext;
   writeContext.magFieldContext = m_cfg.magFieldContext;
 
-  // Loop over the state, and write out the maps
-  for (auto& mmap : m_mappingState.surfaceMaterial) {
-    m_cfg.indexedMaterialWriter->write(writeContext, std::move(mmap));
+  Acts::DetectorMaterialMaps detectorMaterial;
+
+  // Loop over the state, and collect the maps for surfaces
+  for (auto & [ key, value ] : m_mappingState.surfaceMaterial) {
+    detectorMaterial.first.insert({key, std::move(value)});
+  }
+
+  for (auto& imw : m_cfg.materialWriters) {
+    imw->write(writeContext, detectorMaterial);
   }
 }
 
diff --git a/Examples/MaterialMapping/CMakeLists.txt b/Examples/MaterialMapping/CMakeLists.txt
index fde308c05b9707c2f28704e431aa2390d967c379..c5ef9e6858a0e9398b71fec076265f688b5def50 100644
--- a/Examples/MaterialMapping/CMakeLists.txt
+++ b/Examples/MaterialMapping/CMakeLists.txt
@@ -11,9 +11,10 @@ install(TARGETS ACTFWGenericMaterialValidationExample RUNTIME DESTINATION ${CMAK
 
 add_executable(ACTFWGenericMaterialMappingExample src/GenericMaterialMapping.cpp)
 target_include_directories(ACTFWGenericMaterialMappingExample PRIVATE ${Boost_INCLUDE_DIRS})
-target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE ActsCore ACTFWJsonPlugin ActsMaterialMappingPlugin)
+target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE ActsCore ActsMaterialMappingPlugin)
 target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE ACTFramework ACTFWExamplesCommon ACTFWMaterialMapping ACTFWGenericDetector)
 target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE ACTFWRootPlugin)
+target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE ACTFWJsonPlugin)
 target_link_libraries(ACTFWGenericMaterialMappingExample PRIVATE ${Boost_LIBRARIES})
 
 install(TARGETS ACTFWGenericMaterialMappingExample RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp b/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp
index 3f5975a8d7cba59a8c475cdaeed882f5cd2c75c0..d0d14f288d6467c4709759f1fa585c88f15c5f5d 100644
--- a/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp
+++ b/Examples/MaterialMapping/src/detail/MaterialMappingBase.hpp
@@ -17,8 +17,10 @@
 #include "ACTFW/Common/OutputOptions.hpp"
 #include "ACTFW/Framework/Sequencer.hpp"
 #include "ACTFW/MaterialMapping/MaterialMapping.hpp"
-#include "ACTFW/Plugins/Root/RootIndexedMaterialWriter.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/Utilities/Paths.hpp"
 #include "Acts/Detector/TrackingGeometry.hpp"
 #include "Acts/Extrapolator/Navigator.hpp"
@@ -129,20 +131,50 @@ materialMappingExample(int              argc,
       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>();
-  /// The writer of the indexed material
-  FW::Root::RootIndexedMaterialWriter::Config rimConfig(
-      "IndexedMaterialWriter");
-  rimConfig.fileName = materialFileName;
-  auto rimRootWriter
-      = std::make_shared<FW::Root::RootIndexedMaterialWriter>(rimConfig);
 
-  /// The material mapping algorithm
-  FW::MaterialMapping::Config mmAlgConfig(geoContext, mfContext);
-  mmAlgConfig.materialMapper        = smm;
-  mmAlgConfig.trackingGeometry      = tGeometry;
-  mmAlgConfig.indexedMaterialWriter = rimRootWriter;
+  if (vm["output-root"].template as<bool>()) {
+
+    /// The writer of the indexed material
+    FW::Root::RootMaterialWriter::Config rimConfig("MaterialWriter");
+    rimConfig.fileName = materialFileName + ".root";
+    auto rimRootWriter
+        = std::make_shared<FW::Root::RootMaterialWriter>(rimConfig);
+
+    mmAlgConfig.materialWriters.push_back(rimRootWriter);
+  }
+
+  if (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-volume"].template as<bool>();
+    jmConverterCfg.writeData      = vm["mat-output-data"].template as<bool>();
+    // The converter on basis of Json
+    jmConverterCfg.fileName = materialFileName + ".json";
+    // The writer
+    auto jimJsonWriter
+        = std::make_shared<FW::Json::JsonMaterialWriter>(jmConverterCfg);
+
+    mmAlgConfig.materialWriters.push_back(jimJsonWriter);
+  }
 
   // Create the material mapping
   auto mmAlg = std::make_shared<FW::MaterialMapping>(mmAlgConfig);
diff --git a/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp b/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp
index 46593b52dd418e674b215b3fbdf04a722f8338eb..3a5ba6fcfa117ed60a4f67a00ca7ae9f61342702 100644
--- a/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp
+++ b/Examples/MaterialMapping/src/detail/MaterialValidationBase.hpp
@@ -16,7 +16,7 @@
 #include "ACTFW/Common/OutputOptions.hpp"
 #include "ACTFW/Framework/Sequencer.hpp"
 #include "ACTFW/Plugins/BField/BFieldOptions.hpp"
-#include "ACTFW/Plugins/Root/RootIndexedMaterialReader.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialReader.hpp"
 #include "ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp"
 #include "ACTFW/Propagation/PropagationAlgorithm.hpp"
 #include "ACTFW/Propagation/PropagationOptions.hpp"
diff --git a/Plugins/Json/CMakeLists.txt b/Plugins/Json/CMakeLists.txt
index a5a24ba70022a607c59165c89d00b3de63394911..da107b3e79f04fff3a43087385ca1b852f3f09c7 100644
--- a/Plugins/Json/CMakeLists.txt
+++ b/Plugins/Json/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(srcs src/JsonGeometryConverter.cpp)
+set(srcs src/JsonGeometryConverter.cpp src/JsonMaterialWriter.cpp)
 
 add_library(ACTFWJsonPlugin SHARED ${srcs})
 target_include_directories(ACTFWJsonPlugin PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
diff --git a/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp b/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp
index f2018dd230e2d066e5e82b1a116fa22e4b6b708c..06a6453c19f607cb8c520c8062140f747129ce35 100644
--- a/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp
+++ b/Plugins/Json/include/ACTFW/Plugins/Json/JsonGeometryConverter.hpp
@@ -28,6 +28,8 @@ using SurfaceMaterialMap
 
 using VolumeMaterialMap
     = std::map<GeometryID, std::shared_ptr<const IVolumeMaterial>>;
+
+using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>;
 }
 
 namespace FW {
@@ -125,6 +127,9 @@ namespace Json {
       /// The name of the writer
       std::string name = "";
 
+      /// Optionally the file name
+      std::string fileName = "";
+
       /// Steering to handle sensitive data
       bool processSensitives = true;
 
@@ -172,8 +177,7 @@ namespace Json {
     ///
     /// @param surfaceMaterialMap The indexed material map collection
     json
-    materialMapsToJson(
-        std::pair<Acts::SurfaceMaterialMap, Acts::VolumeMaterialMap>& maps);
+    materialMapsToJson(const Acts::DetectorMaterialMaps& maps);
 
     /// Write method
     ///
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..5abda487541854aeae017c763d55de0d5b806947
--- /dev/null
+++ b/Plugins/Json/include/ACTFW/Plugins/Json/JsonMaterialWriter.hpp
@@ -0,0 +1,89 @@
+// 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 "ACTFW/Writers/IWriterT.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 {
+
+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 FW::IWriterT<Acts::DetectorMaterialMaps>
+  {
+
+  public:
+    /// Constructor
+    ///
+    /// @param cfg The configuration struct of the converter
+    JsonMaterialWriter(const JsonGeometryConverter::Config& cfg);
+
+    /// Virtual destructor
+    ~JsonMaterialWriter() override;
+
+    /// Framework name() method
+    std::string
+    name() const final override;
+
+    /// Interface method which writes out the MaterialTrack entities
+    ///
+    /// @param context is the algorithm context in case it is contextual
+    /// @param ism is the indexed surface material
+    FW::ProcessCode
+    write(const AlgorithmContext&           context,
+          const Acts::DetectorMaterialMaps& detMaterial) final override;
+
+  private:
+    /// The config class of the converter
+    JsonGeometryConverter::Config m_cfg;
+
+    /// mutex used to protect multi-threaded writes
+    std::mutex m_write_mutex;
+
+    /// Private access to the logging instance
+    const Acts::Logger&
+    logger() const
+    {
+      return *m_cfg.logger;
+    }
+  };
+
+  inline std::string
+  JsonMaterialWriter::name() const
+  {
+    return m_cfg.name;
+  }
+
+}  // namespace Json
+}  // namespace FW
diff --git a/Plugins/Json/src/JsonGeometryConverter.cpp b/Plugins/Json/src/JsonGeometryConverter.cpp
index dd4b347e7ad09e4793896ef8c664cf87cd67b168..0dedb15657f6aa81fbb594d126ee33010da6f763 100644
--- a/Plugins/Json/src/JsonGeometryConverter.cpp
+++ b/Plugins/Json/src/JsonGeometryConverter.cpp
@@ -142,7 +142,7 @@ FW::Json::JsonGeometryConverter::jsonToMaterialMaps(const json& materialmaps)
 ///
 json
 FW::Json::JsonGeometryConverter::materialMapsToJson(
-    std::pair<Acts::SurfaceMaterialMap, Acts::VolumeMaterialMap>& maps)
+    const Acts::DetectorMaterialMaps& maps)
 {
   DetectorRep detRep;
   // Collect all GeometryIDs per VolumeID for the formatted output
diff --git a/Plugins/Json/src/JsonMaterialWriter.cpp b/Plugins/Json/src/JsonMaterialWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3bbb7a523dd81d0cc5b9bef89f1f12f4dad7e49d
--- /dev/null
+++ b/Plugins/Json/src/JsonMaterialWriter.cpp
@@ -0,0 +1,47 @@
+// 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/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)
+  : FW::IWriterT<Acts::DetectorMaterialMaps>(), m_cfg(cfg)
+{
+  // Validate the configuration
+  if (m_cfg.name.empty()) {
+    throw std::invalid_argument("Missing service name");
+  }
+}
+
+FW::Json::JsonMaterialWriter::~JsonMaterialWriter()
+{
+}
+
+FW::ProcessCode
+FW::Json::JsonMaterialWriter::write(
+    const AlgorithmContext& /*context*/,
+    const Acts::DetectorMaterialMaps& detMaterial)
+{
+
+  FW::Json::JsonGeometryConverter jmConverter(m_cfg);
+
+  auto jout = jmConverter.materialMapsToJson(detMaterial);
+  // write prettified JSON to another file
+  std::string   jsonOutputName = m_cfg.fileName + ".json";
+  std::ofstream ofj(jsonOutputName);
+  ofj << std::setw(4) << jout << std::endl;
+
+  // return success
+  return FW::ProcessCode::SUCCESS;
+}
diff --git a/Plugins/Root/CMakeLists.txt b/Plugins/Root/CMakeLists.txt
index 307ea8976c22697f4d1c00a3f9fc084c0616be5f..d42916c88c209ef680286298127ed564b3e5bd65 100644
--- a/Plugins/Root/CMakeLists.txt
+++ b/Plugins/Root/CMakeLists.txt
@@ -1,15 +1,15 @@
 Examples/Propagation/src/detail/PropagationExampleBase.hppset(srcs include/ACTFW/Plugins/Root/RootExCellWriter.hpp
          include/ACTFW/Plugins/Root/RootExCellWriter.ipp
          include/ACTFW/Plugins/Root/RootPlanarClusterWriter.hpp
-         include/ACTFW/Plugins/Root/RootIndexedMaterialReader.hpp
-         include/ACTFW/Plugins/Root/RootIndexedMaterialWriter.hpp
+         include/ACTFW/Plugins/Root/RootMaterialReader.hpp
+         include/ACTFW/Plugins/Root/RootMaterialWriter.hpp
          include/ACTFW/Plugins/Root/RootMaterialTrackReader.hpp
          include/ACTFW/Plugins/Root/RootMaterialTrackWriter.hpp
          include/ACTFW/Plugins/Root/RootPropagationStepsWriter.hpp
          include/ACTFW/Plugins/Root/RootParticleWriter.hpp
          include/ACTFW/Plugins/Root/RootSimHitWriter.hpp
-         src/RootIndexedMaterialReader.cpp
-         src/RootIndexedMaterialWriter.cpp
+         src/RootMaterialReader.cpp
+         src/RootMaterialWriter.cpp
          src/RootMaterialTrackReader.cpp
          src/RootMaterialTrackWriter.cpp
          src/RootPlanarClusterWriter.cpp
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootIndexedMaterialReader.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialReader.hpp
similarity index 90%
rename from Plugins/Root/include/ACTFW/Plugins/Root/RootIndexedMaterialReader.hpp
rename to Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialReader.hpp
index c7405932c149a56b4e27a643dc9c55b3aaf85e10..3fd242a107367c2f443c98f7e96c757eabdc0591 100644
--- a/Plugins/Root/include/ACTFW/Plugins/Root/RootIndexedMaterialReader.hpp
+++ b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialReader.hpp
@@ -31,12 +31,11 @@ namespace FW {
 
 namespace Root {
 
-  /// @class RootIndexedMaterialReader
+  /// @class RootMaterialReader
   ///
   /// @brief Read the collection of SurfaceMaterial from a file in order to
   /// load it onto the TrackingGeometry
-  class RootIndexedMaterialReader
-      : public FW::IReaderT<Acts::SurfaceMaterialMap>
+  class RootMaterialReader : public FW::IReaderT<Acts::SurfaceMaterialMap>
   {
   public:
     /// @class Config
@@ -97,10 +96,10 @@ namespace Root {
     /// Constructor
     ///
     /// @param cfg configuration struct for the reader
-    RootIndexedMaterialReader(const Config& cfg);
+    RootMaterialReader(const Config& cfg);
 
     /// Virtual destructor
-    ~RootIndexedMaterialReader() override;
+    ~RootMaterialReader() override;
 
     /// Framework name() method
     std::string
@@ -136,7 +135,7 @@ namespace Root {
   };
 
   inline std::string
-  RootIndexedMaterialReader::name() const
+  RootMaterialReader::name() const
   {
     return m_cfg.name;
   }
@@ -145,11 +144,11 @@ namespace Root {
   class RootMaterialDecorator : public Acts::IMaterialDecorator
   {
   public:
-    RootMaterialDecorator(RootIndexedMaterialReader::Config rConfig)
+    RootMaterialDecorator(RootMaterialReader::Config rConfig)
       : m_readerConfig(rConfig)
     {
       // Create the reader with the config
-      RootIndexedMaterialReader reader(m_readerConfig);
+      RootMaterialReader reader(m_readerConfig);
       // Read the map & return it
       reader.read(m_surfaceMaterialMap);
     }
@@ -176,8 +175,8 @@ namespace Root {
     }
 
   private:
-    RootIndexedMaterialReader::Config m_readerConfig;
-    Acts::SurfaceMaterialMap          m_surfaceMaterialMap;
+    RootMaterialReader::Config m_readerConfig;
+    Acts::SurfaceMaterialMap   m_surfaceMaterialMap;
   };
 
 }  // namespace Root
diff --git a/Plugins/Root/include/ACTFW/Plugins/Root/RootIndexedMaterialWriter.hpp b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialWriter.hpp
similarity index 83%
rename from Plugins/Root/include/ACTFW/Plugins/Root/RootIndexedMaterialWriter.hpp
rename to Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialWriter.hpp
index 7b463973fbe2bd34d276d1b3521f23b6b8d2eef7..908771049846f267d7b69663f441cd0e667fb500 100644
--- a/Plugins/Root/include/ACTFW/Plugins/Root/RootIndexedMaterialWriter.hpp
+++ b/Plugins/Root/include/ACTFW/Plugins/Root/RootMaterialWriter.hpp
@@ -7,23 +7,31 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 ///////////////////////////////////////////////////////////////////
-// RootIndexedMaterialWriter.h
+// RootMaterialWriter.h
 ///////////////////////////////////////////////////////////////////
 
 #pragma once
 
+#include <map>
 #include <mutex>
 #include "ACTFW/Framework/ProcessCode.hpp"
 #include "ACTFW/Writers/IWriterT.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"
 #include "TFile.h"
 
 namespace Acts {
-using IndexedSurfaceMaterial
-    = std::pair<GeometryID, std::unique_ptr<const ISurfaceMaterial>>;
+
+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 {
@@ -38,8 +46,7 @@ namespace Root {
   /// It writes out a MaterialTrack which is usually generated from
   /// Geant4 material mapping
 
-  class RootIndexedMaterialWriter
-      : public FW::IWriterT<Acts::IndexedSurfaceMaterial>
+  class RootMaterialWriter : public FW::IWriterT<Acts::DetectorMaterialMaps>
   {
 
   public:
@@ -100,10 +107,10 @@ namespace Root {
     /// Constructor
     ///
     /// @param cfg The configuration struct
-    RootIndexedMaterialWriter(const Config& cfg);
+    RootMaterialWriter(const Config& cfg);
 
     /// Virtual destructor
-    ~RootIndexedMaterialWriter() override;
+    ~RootMaterialWriter() override;
 
     /// Framework name() method
     std::string
@@ -112,10 +119,10 @@ namespace Root {
     /// Interface method which writes out the MaterialTrack entities
     ///
     /// @param context is the algorithm context in case it is contextual
-    /// @param ism is the indexed surface material
+    /// @param detMaterial are the detector material maps
     FW::ProcessCode
-    write(const AlgorithmContext&             context,
-          const Acts::IndexedSurfaceMaterial& ism) final override;
+    write(const AlgorithmContext&           context,
+          const Acts::DetectorMaterialMaps& detMaterial) final override;
 
   private:
     /// The config class
@@ -134,7 +141,7 @@ namespace Root {
   };
 
   inline std::string
-  RootIndexedMaterialWriter::name() const
+  RootMaterialWriter::name() const
   {
     return m_cfg.name;
   }
diff --git a/Plugins/Root/src/RootIndexedMaterialWriter.cpp b/Plugins/Root/src/RootIndexedMaterialWriter.cpp
deleted file mode 100644
index 9111069d2fdc7fbe71548520fa29a8ba32209655..0000000000000000000000000000000000000000
--- a/Plugins/Root/src/RootIndexedMaterialWriter.cpp
+++ /dev/null
@@ -1,211 +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/.
-
-#include "ACTFW/Plugins/Root/RootIndexedMaterialWriter.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::RootIndexedMaterialWriter::RootIndexedMaterialWriter(
-    const FW::Root::RootIndexedMaterialWriter::Config& cfg)
-  : FW::IWriterT<Acts::IndexedSurfaceMaterial>()
-  , 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::RootIndexedMaterialWriter::~RootIndexedMaterialWriter()
-{
-  m_outputFile->Close();
-}
-
-FW::ProcessCode
-FW::Root::RootIndexedMaterialWriter::write(
-    const AlgorithmContext&             context,
-    const Acts::IndexedSurfaceMaterial& ism)
-{
-  // lock the mutex
-  std::lock_guard<std::mutex> lock(m_write_mutex);
-
-  // Change to the output file
-  m_outputFile->cd();
-
-  // Get the Surface material
-  const Acts::ISurfaceMaterial* sMaterial = ism.second.get();
-
-  // get the geometry ID
-  Acts::GeometryID geoID = ism.first;
-  // 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_INFO("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();
-
-  // return success
-  return FW::ProcessCode::SUCCESS;
-}
diff --git a/Plugins/Root/src/RootIndexedMaterialReader.cpp b/Plugins/Root/src/RootMaterialReader.cpp
similarity index 94%
rename from Plugins/Root/src/RootIndexedMaterialReader.cpp
rename to Plugins/Root/src/RootMaterialReader.cpp
index cb4213a39b5d30899eb2f7688329143de9c1f38f..63bc0c23c17bb542043c9227ae556b1ff5c2e7e2 100644
--- a/Plugins/Root/src/RootIndexedMaterialReader.cpp
+++ b/Plugins/Root/src/RootMaterialReader.cpp
@@ -6,7 +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/.
 
-#include "ACTFW/Plugins/Root/RootIndexedMaterialReader.hpp"
+#include "ACTFW/Plugins/Root/RootMaterialReader.hpp"
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/finder.hpp>
 #include <boost/algorithm/string/iter_find.hpp>
@@ -26,8 +26,8 @@
 #include "TKey.h"
 #include "TList.h"
 
-FW::Root::RootIndexedMaterialReader::RootIndexedMaterialReader(
-    const FW::Root::RootIndexedMaterialReader::Config& cfg)
+FW::Root::RootMaterialReader::RootMaterialReader(
+    const FW::Root::RootMaterialReader::Config& cfg)
   : FW::IReaderT<Acts::SurfaceMaterialMap>(), m_cfg(cfg), m_inputFile(nullptr)
 {
   // Validate the configuration
@@ -48,16 +48,15 @@ FW::Root::RootIndexedMaterialReader::RootIndexedMaterialReader(
   }
 }
 
-FW::Root::RootIndexedMaterialReader::~RootIndexedMaterialReader()
+FW::Root::RootMaterialReader::~RootMaterialReader()
 {
   m_inputFile->Close();
 }
 
 FW::ProcessCode
-FW::Root::RootIndexedMaterialReader::read(
-    Acts::SurfaceMaterialMap& sMaterialMap,
-    size_t /*skip*/,
-    const FW::AlgorithmContext* /*ctx*/)
+FW::Root::RootMaterialReader::read(Acts::SurfaceMaterialMap& sMaterialMap,
+                                   size_t /*skip*/,
+                                   const FW::AlgorithmContext* /*ctx*/)
 {
   // lock the mutex
   std::lock_guard<std::mutex> lock(m_read_mutex);
diff --git a/Plugins/Root/src/RootMaterialWriter.cpp b/Plugins/Root/src/RootMaterialWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce76fdcbf9ac49991e048831cfac06e88a19b68e
--- /dev/null
+++ b/Plugins/Root/src/RootMaterialWriter.cpp
@@ -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/.
+
+#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)
+  : FW::IWriterT<Acts::DetectorMaterialMaps>()
+  , 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();
+}
+
+FW::ProcessCode
+FW::Root::RootMaterialWriter::write(
+    const AlgorithmContext&           context,
+    const Acts::DetectorMaterialMaps& detMaterial)
+{
+  // lock the mutex
+  std::lock_guard<std::mutex> lock(m_write_mutex);
+
+  // 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_INFO("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();
+  }
+
+  // return success
+  return FW::ProcessCode::SUCCESS;
+}