diff --git a/algo/ca/core/CMakeLists.txt b/algo/ca/core/CMakeLists.txt
index 5660908bf5265958badf52f2eab3cbb8f2586620..c64de6bf90fb177b129f29ebf17ea9b133be2f6f 100644
--- a/algo/ca/core/CMakeLists.txt
+++ b/algo/ca/core/CMakeLists.txt
@@ -20,6 +20,7 @@ set(SRCS
   ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaInitManager.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaIteration.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaMaterialMap.cxx
+  ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaMaterialMonitor.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaParameters.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaSearchWindow.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/pars/CaStation.cxx
@@ -72,6 +73,7 @@ install(
     pars/CaInitManager.h
     pars/CaIteration.h
     pars/CaMaterialMap.h
+    pars/CaMaterialMonitor.h
     pars/CaParameters.h
     pars/CaSearchWindow.h
     pars/CaStation.h
diff --git a/algo/ca/core/pars/CaMaterialMonitor.cxx b/algo/ca/core/pars/CaMaterialMonitor.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1586b983104f1f6e1f0c8de239bac4dc2916e309
--- /dev/null
+++ b/algo/ca/core/pars/CaMaterialMonitor.cxx
@@ -0,0 +1,160 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov [committer] */
+
+/// \file MaterialMonitor.cxx
+/// \brief Implementation of the MaterialMonitor class
+
+#include "CaMaterialMonitor.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include "AlgoFairloggerCompat.h"
+
+namespace cbm::algo::ca
+{
+
+  namespace
+  {
+    using namespace cbm::algo;
+  }
+
+  void MaterialMonitor::SetMaterial(const ca::MaterialMap* materialMap)
+  {
+    /// construction
+    /// \param  materialMap  Matareial map to be monitored
+
+    fMaterial = materialMap;
+
+    fActiveBinMap.resize(0);
+
+    if (fMaterial) { fActiveBinMap.assign(fMaterial->GetNbins() * fMaterial->GetNbins(), 0); }
+
+    fNhitsTotal   = 0;
+    fNhitsOutside = 0;
+
+    EvaluateStatistics();
+  }
+
+  void MaterialMonitor::MarkActiveBin(float x, float y)
+  {
+    /// mark a bin as active
+    if (!fMaterial) {
+      LOG(fatal) << "MaterialMonitor: material map is not set";
+      return;
+    }
+    int i = fMaterial->GetBin(x, y);
+    fNhitsTotal++;
+    if (i < 0) { fNhitsOutside++; }
+    else {
+      fActiveBinMap[i] = 1;
+    }
+  }
+
+  void MaterialMonitor::EvaluateStatistics()
+  {
+    /// update values of statistical variables with respect to the active map
+
+    fActiveNbins  = 0;
+    fPassiveNbins = 0;
+
+    fActiveRadThickMin  = constants::Undef<double>;
+    fActiveRadThickMax  = constants::Undef<double>;
+    fActiveRadThickMean = constants::Undef<double>;
+
+    fPassiveRadThickMin  = constants::Undef<double>;
+    fPassiveRadThickMax  = constants::Undef<double>;
+    fPassiveRadThickMean = constants::Undef<double>;
+
+    if (!fMaterial) { return; }
+
+    int nBins = fMaterial->GetNbins() * fMaterial->GetNbins();
+
+    if (nBins != (int) fActiveBinMap.size()) {
+      LOG(fatal) << "MaterialMonitor: map of active bins is not consistent with the mterial map: nbins "
+                 << fActiveBinMap.size() << " != " << nBins;
+      return;
+    }
+
+    for (int i = 0; i < nBins; i++) {
+      double r = fMaterial->GetRadThickBin(i);
+      if (fActiveBinMap[i]) {  // active material
+        if (fActiveNbins == 0) {
+          fActiveRadThickMin  = r;
+          fActiveRadThickMax  = r;
+          fActiveRadThickMean = r;
+        }
+        else {
+          fActiveRadThickMin = std::min(fActiveRadThickMin, r);
+          fActiveRadThickMax = std::max(fActiveRadThickMax, r);
+          fActiveRadThickMean += r;
+        }
+        fActiveNbins++;
+      }
+      else {
+        // passive material
+        if (fPassiveNbins == 0) {
+          fPassiveRadThickMin  = r;
+          fPassiveRadThickMax  = r;
+          fPassiveRadThickMean = r;
+        }
+        else {
+          fPassiveRadThickMin = std::min(fPassiveRadThickMin, r);
+          fPassiveRadThickMax = std::max(fPassiveRadThickMax, r);
+          fPassiveRadThickMean += r;
+        }
+        fPassiveNbins++;
+      }
+    }
+    if (fActiveNbins + fPassiveNbins != nBins) {
+      LOG(fatal) << "MaterialMonitor: wrong calculation of N passive / active bins ";
+    }
+    if (fActiveNbins > 0) { fActiveRadThickMean /= fActiveNbins; }
+    if (fPassiveNbins > 0) { fPassiveRadThickMean /= fPassiveNbins; }
+  }
+
+
+  std::string MaterialMonitor::ToString()
+  {
+    /// print statistics to a string
+
+    EvaluateStatistics();
+
+    std::stringstream ss;
+    ss << std::setprecision(2) << std::fixed;
+    ss << "material map " << fName << ". ";
+
+    if (fActiveNbins > 0) {
+      ss << "Active material RL: min " << fActiveRadThickMin * 100. << "%, max " << fActiveRadThickMax * 100.
+         << "%, mean " << fActiveRadThickMean * 100. << "%. ";
+    }
+    else {
+      if (fNhitsTotal > 0) { ss << "No active material. "; }
+      else {
+        ss << "No hits to identify active areas. ";
+      }
+    }
+
+    if (fPassiveNbins > 0) {
+      ss << "Passive material RL: min " << fPassiveRadThickMin * 100. << "%, max " << fPassiveRadThickMax * 100.
+         << "%, mean " << fPassiveRadThickMean * 100. << "%. ";
+    }
+    else {
+      ss << "No passive material. ";
+    }
+
+    if (fNhitsTotal > 0) {
+      if (fNhitsOutside == 0) { ss << "No hits outside of the map. "; }
+      else {
+        ss << "There are " << (100. * fNhitsOutside) / fNhitsTotal << "% hits outside the map!!! ";
+      }
+    }
+    else {
+      ss << "No hit statistics. ";
+    }
+
+    return ss.str();
+  }
+
+}  // namespace cbm::algo::ca
diff --git a/algo/ca/core/pars/CaMaterialMonitor.h b/algo/ca/core/pars/CaMaterialMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..b03a67eec17a6433a362cc0fac54264c90fae322
--- /dev/null
+++ b/algo/ca/core/pars/CaMaterialMonitor.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov [committer] */
+
+/// \file MaterialMonitor.h
+/// \brief Class to collect statistics for ca::MaterialMap
+
+
+#pragma once  // include this header only once per compilation unit
+
+
+#include <string>
+#include <vector>
+
+#include "CaConstants.h"
+#include "CaMaterialMap.h"
+
+namespace cbm::algo::ca
+{
+
+  namespace
+  {
+    using namespace cbm::algo;
+  }
+
+  /// Class to collect statistics for ca::MaterialMap
+  ///
+  class MaterialMonitor {
+  public:
+    /// default constructor
+    MaterialMonitor() : MaterialMonitor(nullptr) {}
+
+    /// constructor
+    /// \param  materialMap  Matareial map to be monitored
+    /// \param  name         Name of the material map
+    MaterialMonitor(const ca::MaterialMap* materialMap, std::string name = "") : fName(name)
+    {
+      SetMaterial(materialMap);
+    }
+
+    /// construction
+    /// \param  materialMap  Matareial map to be monitored
+    void SetMaterial(const ca::MaterialMap* materialMap);
+
+    /// construction
+    /// \param  name Name of the material map
+    void SetName(std::string name) { fName = name; }
+
+    /// reset the map of active bins
+    void ResetActiveBins()
+    {
+      for (auto& v : fActiveBinMap) {
+        v = 0;
+      }
+    }
+
+    /// mark a bin as active
+    void MarkActiveBin(float x, float y);
+
+    /// update values of statistical variables with respect to the active map
+    void EvaluateStatistics();
+
+    /// print statistics to a string
+    std::string ToString();
+
+    /// get number of active bins in the map
+    int GetActiveNbins() const { return fActiveNbins; }
+
+    /// get minimal radiation thickness among all active bins
+    double GetActiveRadThickMin() const { return fPassiveRadThickMin; }
+
+    /// get maximal radiation thickness among all active bins
+    double GetActiveRadThickMax() const { return fPassiveRadThickMax; }
+
+    /// get average radiation thickness among all active bins
+    double GetActiveRadThickMean() const { return fPassiveRadThickMean; }
+
+
+    /// get number of passive bins in the map
+    int GetPassiveNbins() const { return fPassiveNbins; }
+
+    /// get minimal radiation thickness among all passive bins
+    double GetPassiveRadThickMin() const { return fPassiveRadThickMin; }
+
+    /// get maximal radiation thickness among all passive bins
+    double GetPassiveRadThickMax() const { return fPassiveRadThickMax; }
+
+    /// get average radiation thickness among all passive bins
+    double GetPassiveRadThickMean() const { return fPassiveRadThickMean; }
+
+
+    /// get the ration of hits that show up outside the material map
+    double GetRatioOfOutsideHits() const { return fNhitsOutside / (fNhitsTotal + 1.e-8); }
+
+    /// get the number of processed hits
+    double GetNhits() const { return fNhitsTotal; }
+
+  private:
+    const ca::MaterialMap* fMaterial {nullptr};  ///< Pointer to ca::MaterialMap
+    std::string fName {};                        ///< Name of the material map
+
+    std::vector<char> fActiveBinMap {};  ///< Map of active bins in the material map (bins where hits appear)
+
+    int fActiveNbins {constants::Undef<int>};               ///< Active material: number of bins
+    double fActiveRadThickMin {constants::Undef<double>};   ///< Active material: minimal thickness
+    double fActiveRadThickMax {constants::Undef<double>};   ///< Active material: maximal thickness
+    double fActiveRadThickMean {constants::Undef<double>};  ///< Active material: average thickness
+
+    int fPassiveNbins {constants::Undef<int>};               ///< Passive material: number of bins
+    double fPassiveRadThickMin {constants::Undef<double>};   ///< Passive material: minimal thickness
+    double fPassiveRadThickMax {constants::Undef<double>};   ///< Passive material: maximal thickness
+    double fPassiveRadThickMean {constants::Undef<double>};  ///< Passive material: average thickness
+
+    unsigned long fNhitsTotal {0};    ///< number of hits in statistics
+    unsigned long fNhitsOutside {0};  ///< number of hits outside the material map
+  };
+
+}  // namespace cbm::algo::ca
diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt
index 7c9fce58a5122ca222e56a8628ebc4ada00d5504..114f8029b490567e5e2c3d7bb17064a736997c38 100644
--- a/reco/L1/CMakeLists.txt
+++ b/reco/L1/CMakeLists.txt
@@ -44,7 +44,6 @@ set(SRCS
   L1Algo/L1Fit.cxx
   CbmL1MCTrack.cxx
   CbmL1Track.cxx
-  L1Algo/L1MaterialMonitor.cxx
   L1Algo/L1CloneMerger.cxx
   L1Algo/utils/L1AlgoDraw.cxx
   L1Algo/utils/L1AlgoEfficiencyPerformance.cxx
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index df22d57610c3ef5049137c935c3726eb13dd1b28..fb85655b4003fb42406227cb8776ad2c5024c135 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -674,7 +674,7 @@ InitStatus CbmL1::Init()
     LOG(info) << "\033[31;1m-------------------- L1 material -----------------------------\033[0m";
     fMaterialMonitor.clear();
     for (int i = 0; i < fNStations; i++) {
-      L1MaterialMonitor m(&(fpAlgo->GetParameters()->GetThicknessMaps()[i]), Form("station %d", i));
+      ca::MaterialMonitor m(&(fpAlgo->GetParameters()->GetThicknessMaps()[i]), Form("station %d", i));
       LOG(info) << m.ToString();
       fMaterialMonitor.push_back(m);
     }
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index b86e6567ceaa243e98c9cd9693de55c6f0e0a768..239e692043a69985cb8419979c355137e487a8d2 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -55,10 +55,10 @@
 #include "AlgoFairloggerCompat.h"
 #include "CaDataManager.h"
 #include "CaInitManager.h"
+#include "CaMaterialMonitor.h"
 #include "CaMonitor.h"
 #include "CaVector.h"
 #include "L1Algo/L1Algo.h"
-#include "L1MaterialMonitor.h"
 
 class L1Algo;
 class CbmL1MCTrack;
@@ -681,7 +681,7 @@ private:
 
   bool fExtrapolateToTheEndOfSTS {false};
 
-  std::vector<L1MaterialMonitor> fMaterialMonitor {};  ///< material monitoring
+  std::vector<ca::MaterialMonitor> fMaterialMonitor {};  ///< material monitoring
 
   ClassDef(CbmL1, 0);
 };
diff --git a/reco/L1/L1Algo/L1MaterialMonitor.cxx b/reco/L1/L1Algo/L1MaterialMonitor.cxx
deleted file mode 100644
index 9faa29bf3e19684b45ef3118e033586f94c36768..0000000000000000000000000000000000000000
--- a/reco/L1/L1Algo/L1MaterialMonitor.cxx
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Sergey Gorbunov [committer] */
-
-#include "L1MaterialMonitor.h"
-
-#include <Logger.h>
-
-#include <iomanip>
-#include <sstream>
-
-
-void L1MaterialMonitor::SetMaterial(const ca::MaterialMap* materialMap)
-{
-  /// construction
-  /// \param  materialMap  Matareial map to be monitored
-
-  fMaterial = materialMap;
-
-  fActiveBinMap.resize(0);
-
-  if (fMaterial) { fActiveBinMap.assign(fMaterial->GetNbins() * fMaterial->GetNbins(), 0); }
-
-  fNhitsTotal   = 0;
-  fNhitsOutside = 0;
-
-  EvaluateStatistics();
-}
-
-void L1MaterialMonitor::MarkActiveBin(float x, float y)
-{
-  /// mark a bin as active
-  if (!fMaterial) {
-    LOG(fatal) << "L1MaterialMonitor: material map is not set";
-    return;
-  }
-  int i = fMaterial->GetBin(x, y);
-  fNhitsTotal++;
-  if (i < 0) { fNhitsOutside++; }
-  else {
-    fActiveBinMap[i] = 1;
-  }
-}
-
-void L1MaterialMonitor::EvaluateStatistics()
-{
-  /// update values of statistical variables with respect to the active map
-
-  fActiveNbins  = 0;
-  fPassiveNbins = 0;
-
-  fActiveRadThickMin  = constants::Undef<double>;
-  fActiveRadThickMax  = constants::Undef<double>;
-  fActiveRadThickMean = constants::Undef<double>;
-
-  fPassiveRadThickMin  = constants::Undef<double>;
-  fPassiveRadThickMax  = constants::Undef<double>;
-  fPassiveRadThickMean = constants::Undef<double>;
-
-  if (!fMaterial) { return; }
-
-  int nBins = fMaterial->GetNbins() * fMaterial->GetNbins();
-
-  if (nBins != (int) fActiveBinMap.size()) {
-    LOG(fatal) << "L1MaterialMonitor: map of active bins is not consistent with the mterial map: nbins "
-               << fActiveBinMap.size() << " != " << nBins;
-    return;
-  }
-
-  for (int i = 0; i < nBins; i++) {
-    double r = fMaterial->GetRadThickBin(i);
-    if (fActiveBinMap[i]) {  // active material
-      if (fActiveNbins == 0) {
-        fActiveRadThickMin  = r;
-        fActiveRadThickMax  = r;
-        fActiveRadThickMean = r;
-      }
-      else {
-        fActiveRadThickMin = std::min(fActiveRadThickMin, r);
-        fActiveRadThickMax = std::max(fActiveRadThickMax, r);
-        fActiveRadThickMean += r;
-      }
-      fActiveNbins++;
-    }
-    else {
-      // passive material
-      if (fPassiveNbins == 0) {
-        fPassiveRadThickMin  = r;
-        fPassiveRadThickMax  = r;
-        fPassiveRadThickMean = r;
-      }
-      else {
-        fPassiveRadThickMin = std::min(fPassiveRadThickMin, r);
-        fPassiveRadThickMax = std::max(fPassiveRadThickMax, r);
-        fPassiveRadThickMean += r;
-      }
-      fPassiveNbins++;
-    }
-  }
-  if (fActiveNbins + fPassiveNbins != nBins) {
-    LOG(fatal) << "L1MaterialMonitor: wrong calculation of N passive / active bins ";
-  }
-  if (fActiveNbins > 0) { fActiveRadThickMean /= fActiveNbins; }
-  if (fPassiveNbins > 0) { fPassiveRadThickMean /= fPassiveNbins; }
-}
-
-
-TString L1MaterialMonitor::ToString()
-{
-  /// print statistics to a string
-
-  EvaluateStatistics();
-
-  TString s(Form("material map %s. ", fName.Data()));
-
-  if (fActiveNbins > 0) {
-    s += Form("Active material RL: min %.2f%%, max %.2f%%, mean %.2f%%. ", fActiveRadThickMin * 100.,
-              fActiveRadThickMax * 100., fActiveRadThickMean * 100);
-  }
-  else {
-    if (fNhitsTotal > 0) { s += "No active material. "; }
-    else {
-      s += "No hits to identify active areas. ";
-    }
-  }
-
-  if (fPassiveNbins > 0) {
-    s += Form("Passive material RL: min %.2f%%, max %.2f%%, mean %.2f%%. ", fPassiveRadThickMin * 100.,
-              fPassiveRadThickMax * 100., fPassiveRadThickMean * 100);
-  }
-  else {
-    s += "No passive material. ";
-  }
-
-  if (fNhitsTotal > 0) {
-    if (fNhitsOutside == 0) { s += "No hits outside of the map. "; }
-    else {
-      s += Form("There are %f%% hits outside the map!!! ", (100. * fNhitsOutside) / fNhitsTotal);
-    }
-  }
-  else {
-    s += "No hit statistics. ";
-  }
-
-  return s;
-}
diff --git a/reco/L1/L1Algo/L1MaterialMonitor.h b/reco/L1/L1Algo/L1MaterialMonitor.h
deleted file mode 100644
index 285d7db5699967dc3b9b89d6596d5eb0e8dc50b0..0000000000000000000000000000000000000000
--- a/reco/L1/L1Algo/L1MaterialMonitor.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Sergey Gorbunov [committer] */
-
-#ifndef L1MaterialMonitor_h
-#define L1MaterialMonitor_h
-
-
-#include "TString.h"
-
-#include <vector>
-
-#include "CaConstants.h"
-#include "CaMaterialMap.h"
-
-using namespace cbm::algo::ca;
-using namespace cbm::algo;
-
-/// Class to collect statistics for ca::MaterialMap
-///
-class L1MaterialMonitor {
-public:
-  /// default constructor
-  L1MaterialMonitor() : L1MaterialMonitor(nullptr) {}
-
-  /// constructor
-  /// \param  materialMap  Matareial map to be monitored
-  /// \param  name         Name of the material map
-  L1MaterialMonitor(const ca::MaterialMap* materialMap, TString name = "") : fName(name) { SetMaterial(materialMap); }
-
-  /// construction
-  /// \param  materialMap  Matareial map to be monitored
-  void SetMaterial(const ca::MaterialMap* materialMap);
-
-  /// construction
-  /// \param  name Name of the material map
-  void SetName(TString name) { fName = name; }
-
-  /// reset the map of active bins
-  void ResetActiveBins()
-  {
-    for (auto& v : fActiveBinMap) {
-      v = 0;
-    }
-  }
-
-  /// mark a bin as active
-  void MarkActiveBin(float x, float y);
-
-  /// update values of statistical variables with respect to the active map
-  void EvaluateStatistics();
-
-  /// print statistics to a string
-  TString ToString();
-
-  /// get number of active bins in the map
-  int GetActiveNbins() const { return fActiveNbins; }
-
-  /// get minimal radiation thickness among all active bins
-  double GetActiveRadThickMin() const { return fPassiveRadThickMin; }
-
-  /// get maximal radiation thickness among all active bins
-  double GetActiveRadThickMax() const { return fPassiveRadThickMax; }
-
-  /// get average radiation thickness among all active bins
-  double GetActiveRadThickMean() const { return fPassiveRadThickMean; }
-
-
-  /// get number of passive bins in the map
-  int GetPassiveNbins() const { return fPassiveNbins; }
-
-  /// get minimal radiation thickness among all passive bins
-  double GetPassiveRadThickMin() const { return fPassiveRadThickMin; }
-
-  /// get maximal radiation thickness among all passive bins
-  double GetPassiveRadThickMax() const { return fPassiveRadThickMax; }
-
-  /// get average radiation thickness among all passive bins
-  double GetPassiveRadThickMean() const { return fPassiveRadThickMean; }
-
-
-  /// get the ration of hits that show up outside the material map
-  double GetRatioOfOutsideHits() const { return fNhitsOutside / (fNhitsTotal + 1.e-8); }
-
-  /// get the number of processed hits
-  double GetNhits() const { return fNhitsTotal; }
-
-private:
-  const ca::MaterialMap* fMaterial {nullptr};  ///< Pointer to ca::MaterialMap
-  TString fName {};                       ///< Name of the material map
-
-  std::vector<char> fActiveBinMap {};  ///< Map of active bins in the material map (bins where hits appear)
-
-  int fActiveNbins {constants::Undef<int>};               ///< Active material: number of bins
-  double fActiveRadThickMin {constants::Undef<double>};   ///< Active material: minimal thickness
-  double fActiveRadThickMax {constants::Undef<double>};   ///< Active material: maximal thickness
-  double fActiveRadThickMean {constants::Undef<double>};  ///< Active material: average thickness
-
-  int fPassiveNbins {constants::Undef<int>};               ///< Passive material: number of bins
-  double fPassiveRadThickMin {constants::Undef<double>};   ///< Passive material: minimal thickness
-  double fPassiveRadThickMax {constants::Undef<double>};   ///< Passive material: maximal thickness
-  double fPassiveRadThickMean {constants::Undef<double>};  ///< Passive material: average thickness
-
-  unsigned long fNhitsTotal {0};    ///< number of hits in statistics
-  unsigned long fNhitsOutside {0};  ///< number of hits outside the material map
-};
-
-#endif